WinCloudInit.psm1
function Set-WinCloudInit { param( [switch] $Enabled, [ValidateRange(0,99)] [int] $State, [pscredential] $Credential ) Set-Content $PSScriptRoot\state $State if ($PSBoundParameters.ContainsKey('Enabled')) { if ($Enabled) { Set-WinCloudInit -Enabled:$false if (-not $Credential) { $Credential = Get-Credential -UserName $env:USERNAME -Message 'Specify credential' } $user = $Credential.UserName $password = $Credential.GetNetworkCredential().Password $command = 'powershell -Command Start-WinCloudInit' schtasks /Create /TN 'WinCloudInit' /RU $user /RP $password /TR $command /SC ONSTART } else { if (schtasks | Select-String WinCloudInit) { schtasks /Delete /TN 'WinCloudInit' /F } } } elseif ($Credential.UserName -eq 'SYSTEM') { schtasks /Change /TN 'WinCloudInit' /RU 'SYSTEM' } } function Start-WinCloudInit { [CmdletBinding()] param() $Log = Join-Path C:\Windows\Temp "WinCloudInit-$((Get-Date).ToString('MM-dd-yy')).log" "Starting WinCloudInit $(Get-Date)" >> $Log 'Searching for cloud-config.json on floppy/cdrom' >> $Log $Found = $false 2,5 | % { if ($ConfigDrive = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType = $_" -Property DeviceID) { $ConfigPath = Join-Path $ConfigDrive.DeviceID 'cloud-config.json' if (Test-Path $ConfigPath) { $Found = $ConfigPath; return } } } if (-not $Found) { 'Searching for cloud-config.json on local drive' >> $Log $LocalPath = 'C:\WinCloudInit\cloud-config.json' if (Test-Path $LocalPath) { $Found = $LocalPath } } if ($Found) { "Found in $Found" >> $Log $Config = Get-Content $Found -Raw | ConvertFrom-Json | Add-Member -MemberType NoteProperty -Name _Path -Value (Split-Path $Found) -TypeName string -Force -PassThru mkdir C:\WinCloudInit\ -ea SilentlyContinue Copy-Item $Found "C:\WinCloudInit\_$Found" } else { $Msg = 'No config source found' $Msg >> $Log throw $Msg } # state file contains last executed plugin number (for reboot handling) 'Reading <state> file' >> $Log $StatePath = "$PSScriptRoot\state" try { if (-not (Test-Path $StatePath)) { New-Item -Path $StatePath -ItemType File } $State = [int](Get-Content $StatePath) "State is $State" >> $Log } catch { $Msg = 'Invalid state file content' $Msg >> $Log throw $Msg } 'Running plugins:' >> $Log Get-ChildItem $PSScriptRoot\plugins | Sort Name | ? { ($_.Name.Split('-')[0] -as [int]) -gt $State } -pv Plugin | % { try { "Executing $($Plugin.Name)" >> $Log $Output = & $Plugin.FullName -Config $Config -Verbose 4>> $Log } catch { $Msg = "Error during $($Plugin.Name) execution" ($_ | Out-String) >> $Log throw $Msg } $Plugin.Name.Split('-')[0] > $StatePath if (($Output | Select -Last 1) -eq 'reboot') { break } # exit function, continue after reboot } 'Disabling WinCloudInit' >> $Log Set-WinCloudInit -Enabled:$false } |