Skip to content

Instantly share code, notes, and snippets.

@endowdly
Created November 19, 2021 17:14
Show Gist options
  • Save endowdly/97585502efe3bb2213e78f68a6d5e38b to your computer and use it in GitHub Desktop.
Save endowdly/97585502efe3bb2213e78f68a6d5e38b to your computer and use it in GitHub Desktop.
Basic Cmdlet Build Script (No External Tools Needed)
<#PSScriptInfo
.VERSION 1.0.0
.GUID d6ffefc9-781f-4e1b-a46d-0238655151c7
.AUTHOR endowdly
.COMPANYNAME endowdly
.COPYRIGHT 2019
.TAGS
.LICENSEURI
.PROJECTURI
.ICONURI
.EXTERNALMODULEDEPENDENCIES
.REQUIREDSCRIPTS
.EXTERNALSCRIPTDEPENDENCIES
.RELEASENOTES
#>
<#
.DESCRIPTION
A simple build script that can compile PowerShell Cmdlets without external tooling or references.
Uses the native csharp compiler (csc.exe) located in the Framework directory.
Uses 64bit tooling if available and then the highest version of framework tooling available.
Does not use additional toolkits installed by Visual Studio or the user.
Uses the current session's PowerShell assembly.
#>
param ()
# Setup
data Messages {
@{
Warning = @{
DotSourced = 'This script was dot sourced. This is verboten to prevent session pollution!'
CannotInit = 'You are missing core Windows components! Cannot initialize.'
}
Information = @{
DotSourced = 'RECOMMENDATION: Invoke this script using this call operator (&).'
CannotClean = 'RECOMMENDATION: File is likely in use by another process. Close the process and try to build again.'
}
Initialize = 'Initializing...'
Initialized = 'Initialized'
Cleaning = 'Cleaning... '
Cleaned = 'Cleaned'
Building = 'Building... '
Built = 'Built'
Fail = 'Fail'
Nothing = 'Nothing to build!'
LinkingCompiler = 'Linking compiler...'
LinkedCompiler = 'Compiler linked'
Source = 'Source directory exists'
NewSource = 'Creating source directory...'
}
}
data Build {
@{
FrameworkPaths = 'C:\Windows\Microsoft.NET\Framework*'
Framework64 = 'C:\Windows\Microsoft.NET\Framework64'
Framework = 'C:\Windows\Microsoft.NET\Framework64'
}
}
$ErrorActionPreference = 'Stop'
$WarningPreference = 'Continue'
$InformationPreference = 'Continue'
function Get-Indent ($s, $n) { $s.Insert(0, (' ' * 2 * $n)) }
function Write-ColorOutput {
param (
$Object,
[System.ConsoleColor] $ForegroundColor
)
$isHostReady =
($null -ne $Host.UI) -and
($null -ne $Host.UI.RawUI) -and
($null -ne $Host.UI.RawUI.ForegroundColor)
if ($isHostReady -and ($null -ne $ForegroundColor)) {
$originalColor = $Host.UI.RawUI.ForegroundColor
$Host.UI.RawUI.ForegroundColor = $ForegroundColor
}
$Object
if ($null -ne $originalColor) {
$Host.UI.RawUI.ForegroundColor = $originalColor
}
}
# Do not allow sourcing
$IsDotSourced = $MyInvocation.InvocationName -eq '.' -or $MyInvocation.Line -eq ''
if ($IsDotSourced) {
Write-Warning $Messages.Warning.DotSourced
Write-Information $Messages.Information.DotSourced -Tags Recommendation
exit 1
}
Push-Location $PSScriptRoot
Write-Output $Messages.Initialize
try {
Get-Command csc -CommandType Application | Out-Null
Write-Output (Indent $Messages.LinkedCompiler 1)
}
catch {
Write-Output (Indent $Messages.LinkingCompiler 1)
$IsFrameworkDir = Test-Path $Build.FrameworkPaths
$Is64bit = Test-Path $Build.Framework64
if (!$IsFrameworkDir) {
Write-PrettyOutput (Indent $Messages.Fail 1) -ForegroundColor Red
Write-Host
Write-Warning (Indent $Messages.Warning.CannotInit 1)
exit 1
}
$FrameworkDir =
if ($Is64bit) {
$Build.Framework64
}
else {
$Build.Framework
}
Get-ChildItem $FrameworkDir -Directory |
Sort-Object Name |
Select-Object -Last 1 |
Get-ChildItem -Filter csc.exe |
Set-Variable csc
Set-Alias -Name csc -Value $csc.FullName
Write-Output (Indent $Messages.LinkedCompiler 1)
}
if (Test-Path src) {
Write-Output (Indent $Messages.Source 1)
}
else {
Write-Output (Indent $Messages.NewSource 1)
New-Item src -ItemType Directory | Out-Null
Write-Output (Indent $Messages.Source 1)
}
Write-ColorOutput (Indent $Messages.Initialized 1) -ForegroundColor Green
Write-Host
Write-Output $Messages.Cleaning
try {
Join-Path $PSScriptRoot out -OutVariable OutputDirectory |
Get-ChildItem -Recurse -File -OutVariable CleanedFiles |
ForEach-Object {
Write-Information (Indent $_.Name 1)
Remove-Item $_.FullName -Force
}
}
catch {
Write-ColorOutput (Indent $Messages.Fail 1) -ForegroundColor Red
Write-Host
Write-Information $Messages.Information.CannotClean
exit 1
}
New-Item out -ItemType Directory -Force | Out-Null
Write-ColorOutput (Indent $Messages.Cleaned 1) -ForegroundColor Green
Write-Host
# Get every src file
Write-Information $Messages.Building
Get-ChildItem src -Filter *.cs -OutVariable SourceFiles | Foreach-Object { Write-Information (Indent $_.Name 1) }
if (!$SourceFiles) {
Write-ColorOutput (Indent $Messages.Nothing 1) -ForegroundColor Yellow
exit 0
}
# Get Assembly Reference
$PSAssemblyPath = [psobject].Assembly.Location
$TargetName = Split-Path $PSScriptRoot -Leaf
$OutPath = Join-Path out "${TargetName}.dll"
# Compiler Options
$CscArguments = @(
"/reference:$PSAssemblyPath"
"/out:$OutPath"
'/target:library'
'/nologo'
)
$Result = & csc $CscArguments $SourceFiles.FullName 2>&1
if (!$?) {
Write-ColorOutput (Indent $Messages.Fail 1) -ForegroundColor Red
Write-Host
$Result | Foreach-Object { Write-ColorOutput $_ -ForegroundColor Red }
exit 1
}
else {
Write-ColorOutput (Indent $Messages.Built 1) -ForegroundColor Green
Write-Host
}
Pop-Location
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment