From 045e06455a1c26d7a91841d158ca9736e47a7936 Mon Sep 17 00:00:00 2001 From: Shawn Neal Date: Thu, 24 Apr 2014 07:39:58 -0700 Subject: [PATCH] Added WinRM elevated shell wrapper script This script creates an immediately run scheduled task using fresh credentials. This is a generic implementation used by the Chef provisioners. The script gets around several limitations in WinRM. 1. Credential hopping 2. The non-default Administrator account sometimes doesn't have true Administrator access when run through WinRM even with UAC disabled. In short, this script allows commands to run through WinRM just as if they were run directly on the box. --- .../winrm/scripts/elevated_shell.ps1.erb | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 plugins/communicators/winrm/scripts/elevated_shell.ps1.erb diff --git a/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb b/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb new file mode 100644 index 000000000..8e48a219e --- /dev/null +++ b/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb @@ -0,0 +1,95 @@ +$command = "<%= options[:command] %>" +$user = "<%= options[:username] %>" +$password = "<%= options[:password] %>" + +$task_name = "WinRM_Elevated_Shell" +$out_file = "$env:SystemRoot\Temp\WinRM_Elevated_Shell.log" + +if (Test-Path $out_file) { + del $out_file +} + +$task_xml = @' + + + + + {user} + Password + HighestAvailable + + + + IgnoreNew + false + false + true + false + false + + true + false + + true + true + false + false + false + PT2H + 4 + + + + cmd + {arguments} + + + +'@ + +$bytes = [System.Text.Encoding]::Unicode.GetBytes($command) +$encoded_command = [Convert]::ToBase64String($bytes) +$arguments = "/c powershell.exe -EncodedCommand $encoded_command > $out_file 2>&1" + +$task_xml = $task_xml.Replace("{arguments}", $arguments) +$task_xml = $task_xml.Replace("{user}", $user) + +$schedule = New-Object -ComObject "Schedule.Service" +$schedule.Connect() +$task = $schedule.NewTask($null) +$task.XmlText = $task_xml +$folder = $schedule.GetFolder("\") +$folder.RegisterTaskDefinition($task_name, $task, 6, $user, $password, 1, $null) | Out-Null + +$registered_task = $folder.GetTask("\$task_name") +$registered_task.Run($null) | Out-Null + +$timeout = 10 +$sec = 0 +while ( (!($registered_task.state -eq 4)) -and ($sec -lt $timeout) ) { + Start-Sleep -s 1 + $sec++ +} + +# Read the entire file, but only write out new lines we haven't seen before +$numLinesRead = 0 +do { + Start-Sleep -m 100 + + if (Test-Path $out_file) { + $text = (get-content $out_file) + $numLines = ($text | Measure-Object -line).lines + $numLinesToRead = $numLines - $numLinesRead + + if ($numLinesToRead -gt 0) { + $text | select -first $numLinesToRead -skip $numLinesRead | ForEach { + Write-Host "$_" + } + $numLinesRead += $numLinesToRead + } + } +} while (!($registered_task.state -eq 3)) + +$exit_code = $registered_task.LastTaskResult +[System.Runtime.Interopservices.Marshal]::ReleaseComObject($schedule) | Out-Null +exit $exit_code