src/Invoke-CciGetBootstrap.ps1
|
function Invoke-CciGetBootstrap { <# .SYNOPSIS Prepares a freshly built machine in one command. .DESCRIPTION Connects to the tenant, installs the module that tenant nominates for a machine build, imports it, and runs whatever entry point that module declares - so a technician at OOBE types two lines total: Install-Module cciget -Scope CurrentUser Invoke-CciGetBootstrap Nothing here knows what a customization is. The module to install comes from the tenant registry (bootstrapModule) and the final command comes from the installed module's own manifest (PrivateData.CciGet.BootstrapCommand), so cciget stays tenant-generic and a different tenant can nominate something else entirely. The individual steps remain available and unchanged; this only removes the need to remember their order and their arguments. .PARAMETER Tenant Tenant to bootstrap from. Defaults to the configured default feed. .PARAMETER Scope Install scope for the bootstrap module. .PARAMETER Arguments Values for the declared entry point's parameters, e.g. @{ Team = 'platform' }. Anything not supplied is resolved interactively. .PARAMETER Source Force the module source. By default an existing connection is reused, and otherwise the source is resolved the same way Connect-CciGet resolves it. .PARAMETER SkipFinalStep Install and import, but do not run the module's declared entry point. .EXAMPLE Invoke-CciGetBootstrap .EXAMPLE Invoke-CciGetBootstrap -Arguments @{ Team = 'platform' } .EXAMPLE Invoke-CciGetBootstrap -SkipFinalStep #> [CmdletBinding()] param( [string]$Tenant, [ValidateSet('CurrentUser','AllUsers')] [string]$Scope = 'CurrentUser', [hashtable]$Arguments = @{}, [ValidateSet('Auto','Feed','Store')] [string]$Source = 'Auto', [Alias('SkipPublish')] [switch]$SkipFinalStep ) if (-not $Tenant) { $Tenant = (Get-CciGetConfig).defaultFeed } $feed = (_Resolve-CciGetFeed -Tenant $Tenant)[0] $bootstrapProp = $feed.PSObject.Properties['bootstrapModule'] $bootstrapModule = if ($bootstrapProp) { $bootstrapProp.Value } if (-not $bootstrapModule) { throw "cciget: tenant '$($feed.name)' nominates no bootstrap module. Use Connect-CciGet and Install-CciModule directly." } Write-Host "cciget: preparing this machine from the '$($feed.name)' tenant." # Reuse an established connection rather than reconnecting: a second # Connect-CciGet re-resolves the source, so a session deliberately pointed # at the store would silently switch to the feed wherever an Azure CLI # session happens to exist. if ($PSBoundParameters.ContainsKey('Source')) { Connect-CciGet -Tenant $feed.name -Source $Source | Out-Null } elseif ($Script:CciGetSource) { Write-Host "cciget: using the existing '$Script:CciGetSource' connection." } else { Connect-CciGet -Tenant $feed.name | Out-Null } Install-CciModule -Name $bootstrapModule -Tenant $feed.name -Scope $Scope -NoGuidance $resolved = _Resolve-CciModuleName -Name $bootstrapModule -Feed $feed # -Global matters: without it the module loads into cciget's session state # and the caller's session sees none of its commands. Import-Module $resolved -Global -Force $module = Get-Module -Name $resolved | Select-Object -First 1 Write-Host "cciget: imported $resolved $($module.Version)." $command = $null $required = @() $data = $module.PrivateData if ($data -is [hashtable] -and $data.ContainsKey('CciGet')) { $cciget = $data['CciGet'] if ($cciget -is [hashtable]) { if ($cciget.ContainsKey('BootstrapCommand')) { $command = [string]$cciget['BootstrapCommand'] } if ($cciget.ContainsKey('BootstrapParameters')) { $required = @($cciget['BootstrapParameters']) } } } if (-not $command) { Write-Host "cciget: $resolved declares no entry point; nothing further to run." return } if ($SkipFinalStep) { Write-Host "cciget: skipping '$command' as requested. Run it yourself when ready." return } if (-not (Get-Command $command -ErrorAction SilentlyContinue)) { Write-Warning "cciget: $resolved declares '$command' but it is not available. Run it manually once the module is loaded." return } $splat = _Resolve-CciBootstrapArgument -Command $command -Required $required -Supplied $Arguments Write-Host '' Write-Host "cciget: running $command $(($splat.GetEnumerator() | ForEach-Object { "-$($_.Key) $($_.Value)" }) -join ' ')" Write-Host '' & $command @splat } |