Run-InstaPilot.ps1
<#PSScriptInfo
.VERSION 0.1.0 .GUID 279ce402-5fa5-4095-9b92-a5c1a45dcf5f .AUTHOR jacobraffoul@outlook.com.au .COMPANYNAME Raffoul Technologies .COPYRIGHT Raffoul Technologies 2023, All rights reserved. .TAGS .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES #> <# .DESCRIPTION Sample description, for now :) #> param ( [Switch] $Install, [Switch] $Provision ) if (!$Install -and !$Provision) { Write-Host "No arguments provided!" } elseif ($Install -and !$Provision) { InstaPilotInstall } elseif ($Provision -and !$Install) { InstaPilotProvision } else { Write-Host "Bad arguments!" } function InstaPilotInstall { # Create logon script GPO CreateGPO Start-Sleep 2 ## Set time SetTime ## Download NirCMD for WindowsStyle hijacking GetNirCMD start-sleep 5 } function InstaPilotProvision { Start-Sleep 5 ClearScreen ## Resyncing the time SetTime ## Load modules LoadModules ## For good measure :) ClearScreen ## Install driver pack LoadDrivers Start-sleep 2 ## Run a full system update RunUpdates Start-Sleep 2 ## Wait for tenant if device is hybrid HybridWait ## Connect Graph services Connect-MSGraph ## Build GUI and enrol EnrolDevice -ChosenProfile (BuildGUI).SelectedItem } function Write-HostCenter { param($Message) Write-Host; Write-Host ("{0}{1}" -f (' ' * (([Math]::Max(0, $Host.UI.RawUI.BufferSize.Width / 2) - [Math]::Floor($Message.Length / 2)))), $Message) -f Green; Write-Host } function CreateGPO { Write-HostCenter 'Creating GPO for logon script...' New-Item -Path "C:\Windows\System32\GroupPolicy\User\Scripts\scripts.ini" -Force Set-Content "C:\Windows\System32\GroupPolicy\User\Scripts\scripts.ini" -Value ' [Logon] 0CmdLine="%windir%\System32\cmd.exe" 0Parameters="/c "start powershell -ep bypass -command "do { $ping = test-netconnection fast.com } until ($ping.PingSucceeded); run-instapilot.ps1 -provision"" ' -Encoding Unicode -Force -Verbose $MachineGpExtensions = '{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B6664F-4972-11D1-A7CA-0000F87571E3}' $UserGpExtensions = '{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B66650-4972-11D1-A7CA-0000F87571E3}' $contents = Get-Content "C:\Windows\System32\GroupPolicy\gpt.ini" -ErrorAction SilentlyContinue $newVersion = 65537 # 0x00010001 $versionMatchInfo = $contents | Select-String -Pattern 'Version=(.+)' if ($versionMatchInfo.Matches.Groups -and $versionMatchInfo.Matches.Groups[1].Success) { $newVersion += [int]::Parse($versionMatchInfo.Matches.Groups[1].Value) } ( "[General]", "gPCMachineExtensionNames=[$MachineGpExtensions]", "Version=$newVersion", "gPCUserExtensionNames=[$UserGpExtensions]" ) | Out-File -FilePath "C:\Windows\System32\GroupPolicy\gpt.ini" -Encoding ascii gpupdate /wait:10 } function SetTime { Write-HostCenter 'Setting the time server...' net start w32time w32tm /resync /force } function GetNirCMD { Write-HostCenter 'Downloading NirCMD for WindowStyle hijack...' Invoke-WebRequest 'https://www.nirsoft.net/utils/nircmd-x64.zip' -OutFile 'C:\Windows\Temp\nircmd-x64.zip' -Verbose Expand-Archive 'C:\Windows\Temp\nircmd-x64.zip' -DestinationPath 'C:\Windows\System32' -Force -Verbose Remove-Item 'C:\Windows\Temp\nircmd-x64.zip' -Force -Confirm:$false -Verbose } function ClearScreen { Write-HostCenter 'Clearing screen...' nircmd sendkey shift down nircmd sendkey f10 down nircmd sendkey shift up nircmd sendkey f10 up Start-Sleep 1 taskkill /im cmd.exe /f nircmd win hide stitle "Microsoft account" } function LoadModules { Write-HostCenter 'Loading dependencies...' if (Get-PackageProvider -ListAvailable -Name NuGet -ErrorAction SilentlyContinue) { Write-Host "NuGet is already installed!" } else { Install-PackageProvider NuGet -Confirm:$false -Force } $Modules = @( @{ Name = "WindowsAutoPilotIntune"; Version = '5.0' } @{ Name = "PSWindowsUpdate"; Version = '2.2.0.3' } ) foreach ($Module in $Modules) { if ((Get-Module -ListAvailable -Name $Module.Name).Version -like $Module.Version) { Write-Host "$($Module.Name) is already installed. Importing..." Import-Module $Module.Name } else { Write-Host "$($Module.Name) not found! Installing and importing..." Install-Module $Module.Name -RequiredVersion $Module.Version -Confirm:$false -Force | Import-Module } } } function LoadDrivers { if (-not(Test-Path C:\Windows\Temp\DriversFinished.txt)) { Write-HostCenter 'Installing the correct device drivers...' $Device = Get-ComputerInfo -Property CsModel,OSName $Link = (Invoke-WebRequest 'https://raw.githubusercontent.com/RaffTechAU/InstaPilot/main/Drivers.csv' -UseBasicParsing -Verbose).Content | ConvertFrom-CSV | Where-Object { ($_.Model -eq $Device.CsModel) -and ($_.OS -eq $Device.OSName.split(" ")[2]) } | Select-Object -ExpandProperty Link if ($Link) { $Drivers = Start-BitsTransfer -Source $Link -Destination 'C:\Windows\Temp' -Verbose Start-Process msiexec.exe -ArgumentList "/i $Drivers /passive /norestart" -Wait while (((get-process) -like "*msiexec*").count -ge 2) { start-sleep 3 } New-Item C:\Windows\Temp\DriversFinished.txt } else { Write-Host "Can't find drivers!" -f Red } } } function RunUpdates { if (!(test-path C:\Windows\Logs\SkipUpdate.txt) -and !(test-path C:\Windows\Logs\DoUpdate.txt)) { Add-Type -AssemblyName PresentationCore,PresentationFramework $ButtonType = [System.Windows.MessageBoxButton]::YesNo $MessageboxTitle = "Update?" $Messageboxbody = "Run a full system update?" $MessageIcon = [System.Windows.MessageBoxImage]::Information $Result = [System.Windows.MessageBox]::Show($Messageboxbody,$MessageboxTitle,$ButtonType,$messageicon) if ($Result -eq 'Yes') { New-Item -Path C:\Windows\Logs -Name DoUpdate.txt -ItemType File } if ($Result -eq "No") { New-Item -Path C:\Windows\Logs -Name SkipUpdate.txt -ItemType File } } if (test-path C:\Windows\Logs\DoUpdate.txt) { Write-HostCenter 'Running a full system update...' do { $Error.Clear(); Install-WindowsUpdate -AcceptAll -AutoReboot } until ( $Error.Count -eq 0) } } function BuildGUI { Write-HostCenter 'Building provisioning GUI...' [void] [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") $form = New-Object System.Windows.Forms.Form $form.Text = 'InstaPilot IT' $form.Size = New-Object System.Drawing.Size(200,150) $form.StartPosition = 'CenterScreen' $Form.FormBorderStyle = 'Fixed3D' $Form.ControlBox = $false $Form.MaximizeBox = $false $form.TopMost = $true $okButton = New-Object System.Windows.Forms.Button $okButton.Location = New-Object System.Drawing.Point(20,70) $okButton.Size = New-Object System.Drawing.Size(50,25) $okButton.Anchor = 'left' $okButton.Text = 'OK' $okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK $form.AcceptButton = $okButton $form.Controls.Add($okButton) $cancelButton = New-Object System.Windows.Forms.Button $cancelButton.Location = New-Object System.Drawing.Point(115,70) $cancelButton.Size = New-Object System.Drawing.Size(50,25) $cancelButton.Anchor = 'right' $cancelButton.Text = 'Cancel' $cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel $form.CancelButton = $cancelButton $form.Controls.Add($cancelButton) $label = New-Object System.Windows.Forms.Label $label.Location = New-Object System.Drawing.Point(22,5) $label.Size = New-Object System.Drawing.Size(280,20) $label.Text = "Autopilot profile:" $label.Anchor = 'top' $form.Controls.Add($label) $List = New-Object system.Windows.Forms.ComboBox $List.text = "" $List.Location = New-Object System.Drawing.Point(20,30) $List.width = 142 $List.Anchor = 'top' ## Gets list of all AP profiles and adds them to the drop down $Profiles = Get-AutopilotProfile -Verbose [array]::Reverse($Profiles) foreach ($Profile in $Profiles) { [void] $List.Items.Add("$($Profile.displayName)") } ## Gets the current profile assigned to the device (if any) and makes it the default selection $serial = (Get-ComputerInfo -Property BiosSeralNumber -Verbose | Select-Object -ExpandProperty BiosSeralNumber) $CurrentProfile = (Get-AutopilotDevice -serial $serial -Verbose -expand | Select-Object -ExpandProperty deploymentProfile -ErrorAction Ignore | Select-Object -ExpandProperty displayName -ErrorAction Ignore) if ($CurrentProfile) { $List.SelectedItem = $CurrentProfile } else { $List.SelectedIndex = 0 } $form.Controls.Add($List) if ($form.ShowDialog() -ne [System.Windows.Forms.DialogResult]::OK) { exit } return $List } function HybridWait { if (Test-Path C:\Windows\Logs\hybrid.txt) { Write-HostCenter 'Device is hybrid. Waiting for tenant...' for ($i = 1; $i -le 30; $i++ ) { if (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Provisioning\Diagnostics\AutoPilot" | Where-Object {$_.CloudAssignedTenantDomain -ne ""}) { $Error.Clear() ClearScreen ##Create notification to inform operator AP policy has applied Add-Type -AssemblyName PresentationCore,PresentationFramework $ButtonType = [System.Windows.MessageBoxButton]::Ok $MessageboxTitle = "Success!" $Messageboxbody = "Autopilot policies have successfully been detected. Press OK to proceed to sign in." $MessageIcon = [System.Windows.MessageBoxImage]::Information [System.Windows.MessageBox]::Show($Messageboxbody,$MessageboxTitle,$ButtonType,$messageicon) Write-HostCenter "Refreshing OOBE..." RemoveGPO taskkill /im wwahost.exe /f exit } else { Write-Progress -Activity "Waiting for tenant" -PercentComplete ($i/0.3) Start-Sleep -Seconds 10 Write-HostCenter "CloudAssignedTenantDomain registry key is not populated! [$i/30]" -F Yellow -B Black Write-Host } } Write-HostCenter "AP Policy still not present after 5 mins, attempting reboot to try again." Start-Sleep 3 Restart-Computer -Force } } function EnrolDevice($ChosenProfile) { Write-HostCenter 'Processing provisioning request...' ## Find GroupTag $SelectedProfile = Get-AutopilotProfile -Verbose | Where-Object displayName -like $ChosenProfile $SelectedGroup = Get-AutopilotProfileAssignments -id $SelectedProfile.id -Verbose $GroupTag = (Get-AADGroup -groupId $SelectedGroup -Verbose | Select-Object -ExpandProperty membershipRule).split(':')[1].trim(')','"') if (!($GroupTag)) { do { $GroupTag = [Microsoft.VisualBasic.Interaction]::InputBox( "Please manually input a GroupTag", #Description "No GroupTag found for this profile!" #Title ) } until ($GroupTag) } if ("$($SelectedProfile.'@odata.type')" -like "#microsoft.graph.activeDirectoryWindowsAutopilotDeploymentProfile") { $Method = 'Hybrid' } else { $Method = 'Azure' } ## If the chosen profile doesn't match the existing grouptag if (($NULL -ne $CurrentProfile) -and ("$($List.SelectedItem)" -ne "$CurrentProfile")) { Write-HostCenter "Changing groupTag to '$GroupTag'..." ## Sets the groupTag $DeviceID = (Get-AutopilotDevice -serial $serial -Verbose | Select-Object -ExpandProperty id) if ($DeviceID) { Set-AutopilotDevice -id $DeviceID -groupTag $GroupTag -Verbose } Get-Job | Wait-Job ## Repeatedly checks the chosen profile assigned the Autopilot assigned profile until they match do { $CurrentProfile = (Get-AutopilotDevice -Serial $serial -Expand -Verbose | Select-Object -ExpandProperty deploymentProfile -ErrorAction Ignore | Select-Object -ExpandProperty displayName -ErrorAction Ignore) Write-Progress -Activity "Assigning '$($List.SelectedItem)' profile..." -Status "Current profile: $CurrentProfile" start-sleep 30 } until ("$CurrentProfile" -like "$($List.SelectedItem)") } ## Dump variables Write-HostCenter "Importing device with GroupTag '$GroupTag'..." ## Run Commands Install-Script Get-WindowsAutopilotInfo -RequiredVersion 3.5 -Confirm:$false -Force -Verbose Get-WindowsAutopilotInfo.ps1 -GroupTag "$GroupTag" -online if ($Method -eq 'Hybrid') { New-Item -Path C:\Windows\Logs -Name hybrid.txt -ItemType File Restart-Computer -Force } else { ClearScreen Add-Type -AssemblyName PresentationCore,PresentationFramework $ButtonType = [System.Windows.MessageBoxButton]::Ok $MessageboxTitle = "Success!" $Messageboxbody = "The device has been imported successfully. Press OK to proceed to Autopilot." $MessageIcon = [System.Windows.MessageBoxImage]::Information [System.Windows.MessageBox]::Show($Messageboxbody,$MessageboxTitle,$ButtonType,$messageicon) Write-HostCenter "Refreshing OOBE..." RemoveGPO taskkill /im wwahost.exe /f exit } } function RemoveGPO { # Remove logon script GPO Write-HostCenter 'Deleting logon script...' takeown /f "C:\Windows\System32\GroupPolicy\User\Scripts\scripts.ini" /a cmd /C 'icacls "C:\Windows\System32\GroupPolicy\User\Scripts\scripts.ini" /grant EVERYONE:F /q /c' Set-Content "C:\Windows\System32\GroupPolicy\User\Scripts\scripts.ini" -Value '' -Encoding Unicode -Force -Verbose $MachineGpExtensions = '{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B6664F-4972-11D1-A7CA-0000F87571E3}' $UserGpExtensions = '{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B66650-4972-11D1-A7CA-0000F87571E3}' $contents = Get-Content "C:\Windows\System32\GroupPolicy\gpt.ini" -ErrorAction SilentlyContinue $newVersion = 65537 # 0x00010001 $versionMatchInfo = $contents | Select-String -Pattern 'Version=(.+)' if ($versionMatchInfo.Matches.Groups -and $versionMatchInfo.Matches.Groups[1].Success) { $newVersion += [int]::Parse($versionMatchInfo.Matches.Groups[1].Value) } ( "[General]", "gPCMachineExtensionNames=[$MachineGpExtensions]", "Version=$newVersion", "gPCUserExtensionNames=[$UserGpExtensions]" ) | Out-File -FilePath "C:\Windows\System32\GroupPolicy\gpt.ini" -Encoding ascii gpupdate /wait:10 } |