0

A ton of my projects that I work on start off with the same basic layout. I was wondering if there was a way to automate the initial creation of the project. I want to create a solution and all the internal projects with a script. On top of that, I want to be able to create the git repository for this project.

I was hoping there was a way to make this project in a shell script or something like that. If that isn't possible, is there a way to make a template that can be used to create the Solution?

I have done a ton of searching and either I don't know how to word my search correctly, or I can't find anything. I've seen something similar to this making a java project in IntelliJ.

3

1 Answer 1

2

Here's something to get you started. It works with C# projects only and renames all the namespaces of an existing solution. You can clone a directory and it does a simple search and replace. You should also rename the project guids.

<#
.SYNOPSIS
  Renames all the filenames and namespaces of an existing solution or project

.DESCRIPTION
  When a new visual studio solution is cloned, the namespaces usually need
  to be changed, as well as the filenames.

  This script does all that on an existing solution directory.

.PARAMETER Path
  Path to the solution file e.g. MyCompany.MyApp\MyCompany.MyApp.sln

.PARAMETER OldNamespace
  Original namespace of the solution e.g. MyCompany.MyApp

.PARAMETER NewNamespace
  New namespace to replace the original namespace with e.g. MyCompany.NewApp

.INPUTS
  <Inputs if any, otherwise state None>

.OUTPUTS
  <Outputs if any, otherwise state None - example: Log file stored in C:\Windows\Temp\<name>.log>

.NOTES
  Version:        1.0
  Author:         Chui Tey
  Creation Date:  15-08-2018
  Purpose/Change: Initial script development

.EXAMPLE
  .\Rename-Solution.ps1 -Path .\MyCompany.MyApp\MyCompany.MyApp.sln MyCompany.OldApp MyCompany.MyApp [-Verbose]
#>

[CmdletBinding(SupportsShouldProcess)]
param
(
    [Parameter(Mandatory)]
    [string]
    $Path,

    [Parameter(Mandatory)]
    $OldNamespace,

    [Parameter(Mandatory)]
    $NewNamespace
)

#---------------------------------------------------------[Initialisations]--------------------------------------------------------

$ErrorActionPreference = "Stop"

$SolutionPath = $Path
$SolutionDirectory = (Get-Item $SolutionPath).DirectoryName

Write-Verbose "`$SolutionPath=`"$SolutionPath`""
Write-Verbose "`$SolutionDirectory=`"$SolutionDirectory`""

If (-Not (Test-Path $SolutionPath -PathType Leaf))
{
    Write-Error "SolutionPath $SolutionPath not present"
}

If (-Not $SolutionPath.EndsWith(".sln"))
{
    Write-Error "SolutionPath must end with '.sln'"
}

If ($OldNamespace -cnotlike "*.*")
{
    Write-Error "OldNamespace parameter must contain period e.g. 'MyCompany.MyApp'"
}

If ($NewNamespace -cnotlike "*.*")
{
    Write-Error "NewNamespace parameter must contain period e.g. 'MyCompany.MyApp'"
}

#-----------------------------------------------------------[Functions]------------------------------------------------------------


Function Rename-Namespaces
{
    [CmdletBinding(SupportsShouldProcess=$true)]
    param(
        [Parameter(ValueFromPipeline=$True, Mandatory)] $Item,
        [string] $OldNamespace,
        [string] $NewNamespace
    )

    Process
    {
        $OldContent = (Get-Content -Path $item.FullName -Raw)
        If ($OldContent -cmatch $OldNamespace)
        {
            If ($PSCmdlet.ShouldProcess($item.FullName, "Rename-Namespaces"))
            {
                Write-Verbose "Rename-Namespace $($item.FullName)"
                $NewContent = $OldContent -creplace $OldNamespace,$NewNamespace

                # Don't use Set-Content as it appends a new line
                #Set-Content -Path $Item.FullName -Value $NewContent
                [System.IO.File]::WriteAllText($Item.FullName, $NewContent)
            }
        }
    }
}

Function Get-FilesToRenameNamespace
{
    $items = Get-ChildItem -Path $SolutionDirectory -Recurse -File -Filter "*.csproj" 
    $items

    $items = Get-ChildItem -Path $SolutionDirectory -Recurse -File -Filter "*.cs" 
    $items

    $items = Get-ChildItem -Path $SolutionDirectory -Recurse -File -Filter "*.asax" 
    $items

    $items = Get-ChildItem -Path $SolutionDirectory -Recurse -File -Filter "*.cshtml" 
    $items

    $items = Get-ChildItem -Path $SolutionDirectory -Recurse -File -Filter "*.config" 
    $items

    $items = Get-ChildItem -Path $SolutionDirectory -Recurse -File -Filter "*.targets" 
    $items
}

Function Rename-Project($SolutionDirectory, $OldNamespace, $NewNamespace)
{
    Write-Verbose "Renaming csproj"
    Get-ChildItem -ErrorAction SilentlyContinue -File -Recurse -Path $SolutionDirectory -Filter "*$OldNamespace*.csproj" `
    | ForEach-Object {
        $NewName = $_.Name -replace $OldNamespace,$NewNamespace
        Rename-Item -Path $_.FullName $NewName
    }

    Write-Verbose "Renaming directories"
    Get-ChildItem -ErrorAction SilentlyContinue -Directory -Recurse -Path $SolutionDirectory -Filter "*$OldNamespace*" `
    | ForEach-Object {
        $NewName = $_.Name -replace $OldNamespace,$NewNamespace
        Rename-Item -Path $_.FullName $NewName
    }

    Write-Verbose "Renaming project names in sln"
    $OldContent = Get-Content $SolutionPath
    $NewContent = $OldContent -replace $OldNamespace,$NewNamespace
    Set-Content -Path $SolutionPath -Value $NewContent
}


Function Rename-Solution($SolutionDirectory, $OldNamespace, $NewNamespace)
{
    Get-ChildItem -ErrorAction SilentlyContinue -File -Path $SolutionDirectory -Filter "*$OldNamespace*.sln" `
    | ForEach-Object {
        $NewName = $_.Name -replace $OldNamespace,$NewNamespace
        Rename-Item -Path $_.FullName $NewName
    }
}

#-----------------------------------------------------------[Execution]------------------------------------------------------------

Get-FilesToRenameNamespace | Rename-Namespaces -OldNamespace $OldNamespace -NewNamespace $NewNamespace

Rename-Project $SolutionDirectory $OldNamespace $NewNamespace
Rename-Solution $SolutionDirectory $OldNamespace $NewNamespace


Write-Output "End of script"

Script to rename project guids.

<#
.SYNOPSIS
  Renames all the project guids in a solution so that they are unique

.DESCRIPTION
  When a new visual studio solution is cloned, project guids need to change as well.

.PARAMETER Path
  Path to the solution file e.g. MyCompany.MyApp\MyCompany.MyApp.sln

.INPUTS
  <Inputs if any, otherwise state None>

.OUTPUTS
  <Outputs if any, otherwise state None - example: Log file stored in C:\Windows\Temp\<name>.log>

.NOTES
  Version:        1.0
  Author:         Chui Tey
  Creation Date:  15-08-2018
  Purpose/Change: Initial script development

.EXAMPLE
  .\Rename-Solution.ps1 -Path .\MyCompany.MyApp [-Verbose]
#>

[CmdletBinding(SupportsShouldProcess)]
param
(
    [Parameter(Mandatory)]
    [string]
    $Path
)

#---------------------------------------------------------[Initialisations]--------------------------------------------------------

$ErrorActionPreference = "Stop"

$SolutionPath = $Path
$SolutionDirectory = (Get-Item $SolutionPath).DirectoryName

Write-Verbose "`$SolutionPath=`"$SolutionPath`""
Write-Verbose "`$SolutionDirectory=`"$SolutionDirectory`""

If (-Not (Test-Path $SolutionPath -PathType Leaf))
{
    Write-Error "SolutionPath $SolutionPath not present"
}

If (-Not $SolutionPath.EndsWith(".sln"))
{
    Write-Error "SolutionPath must end with '.sln'"
}

#-----------------------------------------------------------[Functions]------------------------------------------------------------

Function Get-ProjectGuid($SolutionPath)
{
    Get-Content $SolutionPath `
    | Where-Object { $_ -match "Project.+ `"(.+)`", `"{([0123456789ABCDEF-]+)}`"" } `
    | ForEach-Object { New-Object PsObject -Property @{ File = $Matches[1]; Guid = $Matches[2] } } `
    | Where-Object { Test-Path -PathType Leaf (Join-Path $SolutionDirectory $_.File) }
}

Function New-Type3Guid([string] $src)
{
    If ($src.Length -eq 0 -or $src -eq $null)
    {
        Write-Error "New-Type3Guid $src must not be empty"
    }

    $md5 = [System.Security.Cryptography.MD5]::Create()
    $hash = $md5.ComputeHash([System.Text.Encoding]::Default.GetBytes($src))
    $md5.Dispose()

    $newGuid = [System.Guid]::new($hash)
    Write-Verbose "New-Type3Guid $src => $newGuid"
    Return $newGuid
}

Function New-ProjectGuidMapping
{
    param
    (
        [Parameter(Mandatory)]
        [string]
        $SolutionPath
    )

    $ProjectGuidMapping = @{}
    Get-ProjectGuid $SolutionPath `
    | ForEach-Object {
        $filename = $_.File
        Write-Verbose "Calling New-Type3Guid $filename"
        $guid = New-Type3Guid $filename
        $ProjectGuidMapping[$_.Guid] = $guid.ToString().ToUpper() 
    }
    Return $ProjectGuidMapping
}

Function Rename-ProjectGuid
{
    [CmdletBinding(SupportsShouldProcess)]
    param ($ProjectGuidMapping)

    $projects = [PSObject[]] (Get-ChildItem -Recurse -File -Path $SolutionDirectory -Filter "*.csproj")
    $solutions = [PSObject[]] (Get-ChildItem -Recurse -File -Path $SolutionDirectory -Filter "*.sln")

    $items = $projects + $solutions
    ForEach ($item in $items)
    {
        $OldContent = Get-Content -Path $item.FullName

        ForEach ($Key in $ProjectGuidMapping.Keys)
        {
            Write-Verbose "Checking key $Key"
            If ($OldContent -cmatch $Key)
            {
                Write-Verbose "Matched $Key in $($Item.FullName)"
                If ($PSCmdlet.ShouldProcess($item.FullName, "Rename-ProjectGuids"))
                {
                    Write-Verbose "Rename-ProjectGuids $($item.FullName) $Key to $($ProjectGuidMapping[$Key])"
                    $NewContent = $OldContent -creplace $Key,$ProjectGuidMapping[$Key]
                    Set-Content -Path $Item.FullName -Value $NewContent
                    $OldContent = $NewContent
                }
            }
        }
    }
}

$ProjectGuidMapping = New-ProjectGuidMapping $SolutionPath
Rename-ProjectGuid $ProjectGuidMapping
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.