├── .gitignore ├── CONTRIBUTING.md ├── Research └── sourcesofinfo.md ├── Undo-WinRMConfig.ps1 ├── chocolateypackaging ├── UndoWinRmRemotingicon256.png ├── cloudywindows128.png ├── readmechocopackaging.md ├── tools │ ├── chocolateyinstall.ps1 │ └── chocolateyuninstall.ps1 └── undo-winrmconfig-during-shutdown.nuspec └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.nupkg -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | ## 3 | 4 | ### Run The Code 5 | 6 | If it is the case, the code will emit the fact that your OS variant is not yet supported. 7 | 8 | ### Find Out What Your Major + Minor OS Version Is: 9 | 10 | Run this code to emit the version string that Undo-WinRMConfig will use. 11 | 12 | **IMPORTANT**: Undo-WinRM only uses the Major + Minor versions to avoid a ton of duplicate registry keys for build level variations of Windows. If you find a build-level variation of the wsman pristine registry key, please file an issue as it may require some re-thinking of how the core engine searches for and finds the right registry data for the pristine key (e.g. we may have to support build level lookup when, and only when, there are build-level variations in the pristine wsman reg key) 13 | 14 | ``` 15 | If ($psversiontable.psversion.major -lt 3) 16 | { $OSMajorMinorVersionString = @(([version](Get-WMIObject Win32_OperatingSystem).version).major,([version](Get-WMIObject Win32_OperatingSystem).version).minor) -join '.'} 17 | Else 18 | { $OSMajorMinorVersionString = @(([version](Get-CIMInstance Win32_OperatingSystem).version).major,([version](Get-CIMInstance Win32_OperatingSystem).version).minor) -join '.'} 19 | Write-Host $OSMajorMinorVersionString 20 | ``` 21 | 22 | 23 | #### If a profile is already available, but you think it needs fixing: 24 | 25 | You can update the code and submit a 26 | pull request with your proposed changes (and an explanation over what use case the original code did not cover that your scenario does). 27 | Please be careful about removing existing code as it may be applicable to scenarios you don't experience in your specific configuration. 28 | 29 | Please be aware that Undo-WinRMConfig will not be allowed to scope drift into a generic revert to pristine utility that reverses all manner of changes made during typical system preparation - it needs to stay laser focused on the core problem of WinRM Configurtion. If you see other common needs similar to the one this code addresses, please propose it in an issue rather than building a pull request that assumes any type of settings reversion is in scope. 30 | 31 | #### If a profile is NOT already available: 32 | 33 | 1. Clone the (Undo-WinRMConfig)[https://github.com/DarwinJS/Undo-WinRMConfig] repository. 34 | 2. Boot a *COMPLETELY PRISTINE* instance of the specific operating system. 35 | 3. Run this code to detect your OS version string: 36 | ``` 37 | If ($psversiontable.psversion.major -lt 3) 38 | { $OSMajorMinorVersionString = @(([version](Get-WMIObject Win32_OperatingSystem).version).major,([version](Get-WMIObject Win32_OperatingSystem).version).minor) -join '.'} 39 | Else 40 | { $OSMajorMinorVersionString = @(([version](Get-CIMInstance Win32_OperatingSystem).version).major,([version](Get-CIMInstance Win32_OperatingSystem).version).minor) -join '.'} 41 | Write-Host $OSMajorMinorVersionString 42 | ``` 43 | 4. Export the registry key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN 44 | 5. Name the file "Pristine-WSMan-" and carefully add it as a here string in Undo-WinRMConfig.ps1. Follow the other examples to ensure that the OS lookup routine will find your addition. Notice that only the first two segments of the OS Version number are used. 45 | 6. Do NOT add any other registry keys to the file 46 | 7. Test that your code works - both to return to pristine and that the system can reconfigure wsman with conventional methods. 47 | 1. Configure wsman 48 | 2. Test that it is working 49 | 3. Run your undo-winrmconfig 50 | 4. Test that winrm is NOT working 51 | 5. Configure wsman AGAINT 52 | 6. Test that it is working again 53 | 8. Once it is all working, create a pull request for your change 54 | 55 | ### System Explorer For Snapshots 56 | 57 | If you suspect that more changes are going on than the registry keys and firewall settings identified in the code in this repository, you can do your own reverse engineering using System Explorer. 58 | 59 | Once you install System Explorer you need to click the "+" to add a new tab and choose "Snapshots". 60 | 61 | This hidden little tool is perfect for reverse engineering configuration changes and it is fast, has a great GUI and works all the way through Windows 2016 (many alternatives aren't fast, have cumbersome interfacces or have compatibility problems). 62 | 63 | This one liner will install it, then just type "systemexplorer" at the command prompt to start it: 64 | ``` 65 | If (!(Test-Path env:chocolateyinstall)) {iwr https://chocolatey.org/install.ps1 -UseBasicParsing | iex} ; cinst -y systemexplorer #for taking snapshots 66 | ``` 67 | -------------------------------------------------------------------------------- /Research/sourcesofinfo.md: -------------------------------------------------------------------------------- 1 | 2 | ## from: http://blog.petegoo.com/2016/05/10/packer-aws-windows/ 3 | # Remove HTTP listener 4 | Remove-Item -Path WSMan:\Localhost\listener\listener* -Recurse 5 | 6 | $Cert = New-SelfSignedCertificate -CertstoreLocation Cert:\LocalMachine\My -DnsName "packer" 7 | New-Item -Path WSMan:\LocalHost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $Cert.Thumbprint -Force 8 | 9 | # WinRM 10 | write-output "Setting up WinRM" 11 | write-host "(host) setting up WinRM" 12 | 13 | cmd.exe /c winrm quickconfig -q 14 | cmd.exe /c winrm set "winrm/config" '@{MaxTimeoutms="1800000"}' 15 | cmd.exe /c winrm set "winrm/config/winrs" '@{MaxMemoryPerShellMB="1024"}' 16 | cmd.exe /c winrm set "winrm/config/service" '@{AllowUnencrypted="true"}' 17 | cmd.exe /c winrm set "winrm/config/client" '@{AllowUnencrypted="true"}' 18 | cmd.exe /c winrm set "winrm/config/service/auth" '@{Basic="true"}' 19 | cmd.exe /c winrm set "winrm/config/client/auth" '@{Basic="true"}' 20 | cmd.exe /c winrm set "winrm/config/service/auth" '@{CredSSP="true"}' 21 | cmd.exe /c winrm set "winrm/config/listener?Address=*+Transport=HTTPS" "@{Port=`"5986`";Hostname=`"packer`";CertificateThumbprint=`"$($Cert.Thumbprint)`"}" 22 | cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes 23 | cmd.exe /c netsh firewall add portopening TCP 5986 "Port 5986" 24 | cmd.exe /c net stop winrm 25 | cmd.exe /c sc config winrm start= auto 26 | cmd.exe /c net start winrm 27 | 28 | 29 | 30 | From: http://www.hurryupandwait.io/blog/creating-windows-base-images-for-virtualbox-and-hyper-v-using-packer-boxstarter-and-vagrant 31 | Set-NetFirewallRule -Name WINRM-HTTP-In-TCP-PUBLIC -RemoteAddress Any 32 | Enable-WSManCredSSP -Force -Role Server 33 | 34 | Enable-PSRemoting -Force -SkipNetworkProfileCheck 35 | winrm set winrm/config/client/auth '@{Basic="true"}' 36 | winrm set winrm/config/service/auth '@{Basic="true"}' 37 | winrm set winrm/config/service '@{AllowUnencrypted="true"}' 38 | 39 | 40 | #from: https://github.com/joescii/packer-windows-example/blob/master/setup.ps1 41 | cmd.exe /c winrm quickconfig -q 42 | cmd.exe /c winrm quickconfig '-transport:http' 43 | cmd.exe /c winrm set "winrm/config" '@{MaxTimeoutms="1800000"}' 44 | cmd.exe /c winrm set "winrm/config/winrs" '@{MaxMemoryPerShellMB="512"}' 45 | cmd.exe /c winrm set "winrm/config/service" '@{AllowUnencrypted="true"}' 46 | cmd.exe /c winrm set "winrm/config/client" '@{AllowUnencrypted="true"}' 47 | cmd.exe /c winrm set "winrm/config/service/auth" '@{Basic="true"}' 48 | cmd.exe /c winrm set "winrm/config/client/auth" '@{Basic="true"}' 49 | cmd.exe /c winrm set "winrm/config/service/auth" '@{CredSSP="true"}' 50 | cmd.exe /c winrm set "winrm/config/listener?Address=*+Transport=HTTP" '@{Port="5985"}' 51 | cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes 52 | cmd.exe /c netsh firewall add portopening TCP 5985 "Port 5985" 53 | cmd.exe /c net stop winrm 54 | cmd.exe /c sc config winrm start= auto 55 | cmd.exe /c net start winrm 56 | 57 | ## from: https://github.com/ricardclau/packer-demos/blob/master/provisioners/powershell/configure-winrm.ps1 58 | 59 | winrm quickconfig -q 60 | winrm quickconfig -transport:http 61 | winrm set winrm/config '@{MaxTimeoutms="7200000"}' 62 | winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="0"}' 63 | winrm set winrm/config/winrs '@{MaxProcessesPerShell="0"}' 64 | winrm set winrm/config/winrs '@{MaxShellsPerUser="0"}' 65 | winrm set winrm/config/service '@{AllowUnencrypted="true"}' 66 | winrm set winrm/config/service/auth '@{Basic="true"}' 67 | winrm set winrm/config/client/auth '@{Basic="true"}' 68 | winrm set winrm/config/listener?Address=*+Transport=HTTP '@{Port="5985"} ' 69 | 70 | netsh advfirewall firewall set rule group="remote administration" new enable=yes 71 | netsh firewall add portopening TCP 5985 "Port 5985" 72 | net stop winrm 73 | sc.exe config winrm start= auto 74 | net start winrm 75 | 76 | ## From: https://gist.github.com/zachtuttle/6a9d05e40c9a6b6c51bd6dc93e05c8a4 77 | 78 | winrm quickconfig -q 79 | winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="2048"}' 80 | winrm set winrm/config/winrs '@{MaxConcurrentUsers="100"}' 81 | winrm set winrm/config/winrs '@{MaxProcessesPerShell="0"}' 82 | winrm set winrm/config/winrs '@{MaxShellsPerUser="0"}' 83 | winrm set winrm/config '@{MaxTimeoutms="7200000"}' 84 | winrm set winrm/config/service '@{AllowUnencrypted="true"}' 85 | winrm set winrm/config/service/auth '@{Basic="true"}' 86 | winrm set winrm/config/service/auth '@{CredSSP="true"}' 87 | winrm set winrm/config/client '@{TrustedHosts="*"}' 88 | 89 | 90 | # open port 5985 in the internal Windows firewall to allow WinRM communication 91 | netsh advfirewall firewall add rule name="WinRM 5985" protocol=TCP dir=in localport=5985 action=allow 92 | 93 | net stop winrm 94 | sc config winrm start=auto 95 | net start winrm 96 | -------------------------------------------------------------------------------- /Undo-WinRMConfig.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Revert WinRM to a pristine state. 4 | See this post for full details on why this code is helpful: https://cloudywindows.io/winrm-for-provisioning---close-the-door-on-the-way-out-eh/ 5 | .DESCRIPTION 6 | CloudyWindows.io DevOps Automation: https://github.com/DarwinJS/CloudyWindowsAutomationCode 7 | Why and How Blog Post: https://cloudywindows.io/winrm-for-provisioning---close-the-door-when-you-are-done-eh/ 8 | Invoke-Expression (Invoke-WebRequest -UseBasicParsing -Uri 'https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/blob/master/Undo-WinRMConfig/Undo-WinRMConfig.ps1') 9 | Invoke-WebRequest -UseBasicParsing -Uri 'https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/blob/master/Undo-WinRMConfig/Undo-WinRMConfig.ps1' -outfile $env:public\Undo-WinRMConfig.ps1 ; & $env:public\Undo-WinRMConfig.ps1 -immediately 10 | Contributing New Undo Profiles: https://github.com/DarwinJS/Undo-WinRMConfig/blob/master/readme.md 11 | 12 | Disclaimer - this code was engineered and tested on Server 2012 R2 and Server 2016. 13 | 14 | Many windows remote orchestration tools (e.g. Packer) instruct you to completely open up winrm permissions in a way that is not safe for production. 15 | Usually there is no built in method nor instruction on how to re-secure it or shut it back down. 16 | The assumption most likely being that you would handle proper configuration as a part of production deployment. 17 | This is not a least privileged approach - depending on how big your company is and how widely your hypervisor templates are used - this is a disaster waiting to happen. So I feel leaving it in a disabled state by default is the far safer option. 18 | To complicate things, if you attempt to secure winrm or shut it down as your last step in orchestration you slam the door on the orchestration system and it marks the attempt as a failure. 19 | Due to imprecise timing, start up tasks that disable winrm could conflict with a subsequent attempt to re-enable it on the next boot for final configuration steps (especially if you are building a hypervisor template). 20 | This self-deleting shutdown task performs the disable on the first shutdown and deletes itself. 21 | If a system shutsdown extremely quickly there is some risk that the shutdown job would not be deleted - but in testing on AWS (very fast shutdown), there have not been an observed problems. 22 | Updates and more information on ways to use this script are here: https://github.com/DarwinJS/CloudyWindowsAutomationCode/blob/master/Undo-WinRMConfig/readme.md 23 | .COMPONENT 24 | CloudyWindows.io 25 | .ROLE 26 | Provisioning Automation 27 | .PARAMETER RunImmediately 28 | Specifies list of semi-colon seperated number ids of local Devices to initialize. Devices appear in HKLM:SYSTEM\CurrentControlSet\Services\disk\Enum. 29 | .PARAMETER RemoveShutdownScriptConfig 30 | Cancels running the script at the next shutdown by removing the shutdown configuration and files 31 | .PARAMETER Version 32 | Emits the version and exits. 33 | .EXAMPLE 34 | Invoke-Expression (invoke-webrequest -uri 'https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/blob/master/Undo-WinRMConfig/Undo-WinRMConfig.ps1') 35 | 36 | Run directly from github with no parameters - sets up shutdown script to reseal winRM. 37 | .EXAMPLE 38 | Invoke-webrequest -uri 'https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/blob/master/Undo-WinRMConfig/Undo-WinRMConfig.ps1' -outfile $env:public\Undo-WinRMConfig.ps1 ; & $env:public\Undo-WinRMConfig.ps1 -immediately 39 | 40 | Download dynamically from github and run immediately. 41 | #> 42 | Param ( 43 | [switch]$RunImmediately, 44 | [switch]$RemoveShutdownScriptConfig, 45 | [switch]$Version 46 | ) 47 | 48 | $ThisScriptVersion = '1.2.0' 49 | 50 | If ($version) 51 | { 52 | Write-Host "$ThisScriptVersion" 53 | Exit 0 54 | } 55 | 56 | Function Setup-Undo { 57 | 58 | Write-Host "`r`n`r`nUndo-WinRMConfig Version $ThisScriptVersion`r`n`r`n" 59 | 60 | #This has to work for Win7 (no get-ciminstance) and Nano (no get-wmiobject) - each of which specially construct win32_operatingsystem.version to handle before and after Windows 10 version numbers (which are in different registry keys) 61 | If ($psversiontable.psversion.major -lt 3) 62 | { $OSMajorMinorVersionString = @(([version](Get-WMIObject Win32_OperatingSystem).version).major,([version](Get-WMIObject Win32_OperatingSystem).version).minor) -join '.' } 63 | Else 64 | { $OSMajorMinorVersionString = @(([version](Get-CIMInstance Win32_OperatingSystem).version).major,([version](Get-CIMInstance Win32_OperatingSystem).version).minor) -join '.' } 65 | 66 | If (!(Test-Path "variable:Pristine-WSMan-${OSMajorMinorVersionString}.reg")) 67 | { 68 | Throw "Undo-WinRMConfig does not have Pristine WSMan .REG file for your OS version $OSMajorMinorVersionString, if you would like to create and contribute one, please see: " 69 | Exit 5 70 | } 71 | 72 | #Build the undo script based on parameters 73 | [string]$UndoWinRMScript = @' 74 | 75 | If (!$PSScriptRoot) {$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent} 76 | 77 | #This has to work for Win7 (no get-ciminstance) and Nano (no get-wmiobject) - each of which specially construct win32_operatingsystem.version to handle before and after Windows 10 version numbers (which are in different registry keys) 78 | If ($psversiontable.psversion.major -lt 3) 79 | { $OSMajorMinorVersionString = @(([version](Get-WMIObject Win32_OperatingSystem).version).major,([version](Get-WMIObject Win32_OperatingSystem).version).minor) -join '.' } 80 | Else 81 | { $OSMajorMinorVersionString = @(([version](Get-CIMInstance Win32_OperatingSystem).version).major,([version](Get-CIMInstance Win32_OperatingSystem).version).minor) -join '.' } 82 | 83 | Write-Host "Disabling all Enabled Firewall rules that address port 5985 or 5896 directly" 84 | $EnabledInboundRMPorts = @(New-object -comObject HNetCfg.FwPolicy2).rules | where-object {($_.LocalPorts -ilike '*5985*') -AND ($_.Enabled -ilike 'True')} 85 | $EnabledInboundRMPorts += @(New-object -comObject HNetCfg.FwPolicy2).rules | where-object {($_.LocalPorts -ilike '*5986*') -AND ($_.Enabled -ilike 'True')} 86 | 87 | ForEach ($FirewallRuleName in $EnabledInboundRMPorts) 88 | { 89 | Write-Host "Disabling firewall rule that addresses remoting: `"$($FirewallRuleName.Name)`"" 90 | netsh advfirewall firewall set rule name="$($FirewallRuleName.Name)" new enable=No 91 | } 92 | 93 | Write-Host "Undoing changes for Enable-PSRemoting, Enable-WSManCredSSP and winrm configuration commands" 94 | 95 | Write-Host "Remove LocalAccountTokenFilterPolicy added by winrm configuration" 96 | #This key is symlinked into "Wow6432Node" - both locations are handled by one delete 97 | $regkeypath ='HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system' 98 | If (!((Get-ItemProperty $regkeypath).LocalAccountTokenFilterPolicy -eq $null)) 99 | {Remove-ItemProperty -path $regkeypath -name LocalAccountTokenFilterPolicy} 100 | 101 | Write-Host "Enable-PSRemoting changes will be removed by undoing WSMAN changes" 102 | Write-Host "Enable-WSManCredSSP client or server changes will be removed by undoing WSMAN changes" 103 | 104 | #Remove WSMAN Key before importing pristine .REG 105 | Remove-Item 'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN' -Recurse -Force 106 | 107 | ForEach ($File in (Get-ChildItem "$PSScriptRoot\*${OSMajorMinorVersionString}.reg" | sort-object Name)) 108 | { 109 | Write-Host "Importing $OSMajorMinorVersionString\$($File.name)" 110 | reg.exe import "$($File.fullname)" 111 | } 112 | '@ 113 | 114 | If ($RunImmediately) 115 | { 116 | Write-Output 'Undoing WinRM Config Right Now (do NOT execute this over remoting or this code will not complete)...' 117 | Invoke-Command -ScriptBlock [Scriptblock]::Create($UndoWinRMScript) 118 | exit 0 119 | } 120 | else 121 | { 122 | Write-Output 'Undoing WinRM Config On Next Shutdown' 123 | } 124 | 125 | #Write a file and call it in a machine shutdown script 126 | $psScriptsFile = "$env:windir\System32\GroupPolicy\Machine\Scripts\psscripts.ini" 127 | $Key1 = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\Shutdown\0' 128 | $Key2 = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts\Shutdown\0' 129 | $keys = @($key1,$key2) 130 | $scriptpath = "$env:windir\System32\GroupPolicy\Machine\Scripts\Shutdown\Undo-WinRMConfig.ps1" 131 | $scriptfilename = (Split-Path -leaf $scriptpath) 132 | $ScriptFolder = (Split-Path -parent $scriptpath) 133 | $FileContents = Get-Variable -name "Pristine-WSMan-${OSMajorMinorVersionString}.reg" -ValueOnly 134 | New-Item -ItemType Directory -Force -Path $ScriptFolder 135 | Set-Content -Path "$ScriptFolder\Pristine-WSMan-${OSMajorMinorVersionString}.reg" -Value $FileContents 136 | 137 | $selfdeletescript = @" 138 | Start-Sleep -milliseconds 500 139 | Remove-Item -Path "$key1" -Force -Recurse -ErrorAction SilentlyContinue 140 | Remove-Item -Path "$key2" -Force -Recurse -ErrorAction SilentlyContinue 141 | Remove-Item -Path $scriptpath -Force -ErrorAction SilentlyContinue 142 | Get-ChildItem "$env:windir\System32\GroupPolicy\Machine\Scripts\Shutdown\*${OSMajorMinorVersionString}.reg" | remove-item -force 143 | If (Test-Path $psScriptsFile) 144 | { 145 | (Get-Content "$psScriptsFile") -replace '0CmdLine=$scriptfilename', '' | Set-Content "$psScriptsFile" 146 | (Get-Content "$psScriptsFile") -replace '0Parameters=', '' | Set-Content "$psScriptsFile" 147 | } 148 | "@ 149 | 150 | $selfdeletescript =[Scriptblock]::Create($selfdeletescript) 151 | 152 | If ($RemoveShutdownScriptConfig) 153 | { 154 | Write-Host "Removing previously setup shutdown script" 155 | Invoke-Command -ScriptBlock $selfdeletescript 156 | exit $? 157 | } 158 | 159 | #Add the cleanup script block as a scheduled job executed immediately at the end of the shutdown script (if we aren't running immediately) 160 | $UndoWinRMScript += "Register-ScheduledJob -Name CleanUpWinRM -RunNow -ScheduledJobOption @{RunElevated=$True;ShowInTaskScheduler=$True;RunWithoutNetwork=$True} -ScriptBlock $selfdeletescript" 161 | 162 | Write-Host "Creating $scriptpath, with the following contents:" 163 | Write-Host '*******************' 164 | Write-Host "$UndoWinRMScript" 165 | Write-Host '*******************`r`n`r`n' 166 | If (!(Test-Path $ScriptFolder)) {New-Item $ScriptFolder -type Directory -force | Out-null} 167 | Set-Content -path $scriptpath -value $UndoWinRMScript 168 | 169 | Foreach ($Key in $keys) 170 | { 171 | Write-Host "Creating $Key" 172 | New-Item -Path $key -Force | out-null 173 | New-ItemProperty -Path $key -Name GPO-ID -Value LocalGPO -Force | out-null 174 | New-ItemProperty -Path $key -Name SOM-ID -Value Local -Force | out-null 175 | New-ItemProperty -Path $key -Name FileSysPath -Value "$env:windir\System32\GroupPolicy\Machine" -Force | out-null 176 | New-ItemProperty -Path $key -Name DisplayName -Value "Local Group Policy" -Force | out-null 177 | New-ItemProperty -Path $key -Name GPOName -Value "Local Group Policy" -Force | out-null 178 | New-ItemProperty -Path $key -Name PSScriptOrder -Value 1 -PropertyType "DWord" -Force | out-null 179 | 180 | $key = "$key\0" 181 | New-Item -Path $key -Force | out-null 182 | New-ItemProperty -Path $key -Name "Script" -Value $scriptfilename -Force | out-null 183 | New-ItemProperty -Path $key -Name "Parameters" -Value $parameters -Force | out-null 184 | New-ItemProperty -Path $key -Name "IsPowershell" -Value 1 -PropertyType "DWord" -Force | out-null 185 | New-ItemProperty -Path $key -Name "ExecTime" -Value 0 -PropertyType "QWord" -Force | out-null 186 | } 187 | 188 | Write-Host "Updating $psScriptsFile" 189 | If (!(Test-Path $psScriptsFile)) {New-Item $psScriptsFile -type file -force} 190 | "[Shutdown]" | Out-File $psScriptsFile 191 | "0CmdLine=$scriptfilename" | Out-File $psScriptsFile -Append 192 | "0Parameters=$parameters" | Out-File $psScriptsFile -Append 193 | 194 | Write-Host "`r`n`r`nUndo-WinRMConfig (v${ThisScriptVersion}) is staged to run at next shutdown. To unstage, run 'Undo-WinRMConfig -RemoveShutdownScriptConfig'" 195 | } 196 | 197 | ${Pristine-WSMan-10.0.reg} = @' 198 | Windows Registry Editor Version 5.00 199 | 200 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN] 201 | "ServiceStackVersion"="3.0" 202 | "StackVersion"="2.0" 203 | 204 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\AutoRestartList] 205 | 206 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\CertMapping] 207 | 208 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Client] 209 | 210 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Listener] 211 | 212 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Listener\*+HTTP] 213 | "Port"=dword:00001761 214 | "uriprefix"="wsman" 215 | 216 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin] 217 | 218 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Event Forwarding Plugin] 219 | "ConfigXML"="" 220 | 221 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Microsoft.PowerShell] 222 | "ConfigXML"=" " 223 | 224 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Microsoft.PowerShell.Workflow] 225 | "ConfigXML"=" " 226 | 227 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Microsoft.PowerShell32] 228 | "ConfigXML"=" " 229 | 230 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Microsoft.Windows.ServerManagerWorkflows] 231 | "ConfigXML"=" " 232 | 233 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\SEL Plugin] 234 | "ConfigXML"=" " 235 | 236 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\WMI Provider] 237 | "ConfigXML"="" 238 | 239 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\SafeClientList] 240 | "WSManSafeClientList"=hex:00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,01 241 | 242 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Service] 243 | "allow_remote_requests"=dword:00000001 244 | 245 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\WinRS] 246 | 247 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\WinRS\CustomRemoteShell] 248 | 249 | '@ 250 | 251 | ${Pristine-WSMan-6.3.reg} = @' 252 | Windows Registry Editor Version 5.00 253 | 254 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN] 255 | "StackVersion"="2.0" 256 | "ServiceStackVersion"="3.0" 257 | "WtrPresent"=dword:00000000 258 | "UpdatedConfig"="E6F6821F-51CC-4FEC-8E46-40C75C0CAD27" 259 | 260 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\AutoRestartList] 261 | 262 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\CertMapping] 263 | 264 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Client] 265 | 266 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Listener] 267 | 268 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Listener\*+HTTP] 269 | "hostname"="" 270 | "uriprefix"="wsman" 271 | "certThumbprint"="" 272 | "Port"=dword:00001761 273 | "enabled"=dword:00000001 274 | 275 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin] 276 | 277 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Event Forwarding Plugin] 278 | "ConfigXML"="" 279 | 280 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Microsoft.PowerShell] 281 | "ConfigXML"="" 282 | 283 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Microsoft.PowerShell.Workflow] 284 | "ConfigXML"="" 285 | 286 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Microsoft.PowerShell32] 287 | "ConfigXML"="" 288 | 289 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Microsoft.Windows.ServerManagerWorkflows] 290 | "ConfigXML"="" 291 | 292 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\SEL Plugin] 293 | "ConfigXML"=" " 294 | 295 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\WMI Provider] 296 | "ConfigXML"="" 297 | 298 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\SafeClientList] 299 | 300 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Service] 301 | "allow_remote_requests"=dword:00000001 302 | 303 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\WinRS] 304 | 305 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\WinRS\CustomRemoteShell] 306 | 307 | '@ 308 | 309 | ${Pristine-WSMan-6.1.reg} = @' 310 | Windows Registry Editor Version 5.00 311 | 312 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN] 313 | "StackVersion"="2.0" 314 | "SupportsCompatListeners"=dword:00000001 315 | "UpdatedConfig"="58262FF8-3F83-4B48-A1FB-054FA5700982" 316 | 317 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\CertMapping] 318 | 319 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Client] 320 | 321 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Listener] 322 | 323 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin] 324 | 325 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Event Forwarding Plugin] 326 | "ConfigXML"="" 327 | 328 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Microsoft.PowerShell] 329 | "ConfigXML"=" " 330 | 331 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\Microsoft.ServerManager] 332 | "ConfigXML"=" " 333 | 334 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\SEL Plugin] 335 | "ConfigXML"="" 336 | 337 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\WMI Provider] 338 | "ConfigXML"="" 339 | 340 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Service] 341 | 342 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\WinRS] 343 | 344 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\WinRS\CustomRemoteShell] 345 | 346 | '@ 347 | 348 | Setup-Undo 349 | -------------------------------------------------------------------------------- /chocolateypackaging/UndoWinRmRemotingicon256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/28b3070bd56982f98274ce31629fa6f7aedb7612/chocolateypackaging/UndoWinRmRemotingicon256.png -------------------------------------------------------------------------------- /chocolateypackaging/cloudywindows128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/28b3070bd56982f98274ce31629fa6f7aedb7612/chocolateypackaging/cloudywindows128.png -------------------------------------------------------------------------------- /chocolateypackaging/readmechocopackaging.md: -------------------------------------------------------------------------------- 1 | 2 | # Dual Purposing To Run Utility Scripts In and Out of Chocolatey 3 | 4 | The structure of this chocolatey package enables: 5 | * the core code to be a plain shell script that can be pulled directly from the web or copied to a target system 6 | * the chocolatey package to a wrapper / additional execution mechanism 7 | * the core code and its documentation to be the primary thing seen when visiting the repository page 8 | * the chocolatey packaging to all be in a subfolder below the primary code -------------------------------------------------------------------------------- /chocolateypackaging/tools/chocolateyinstall.ps1: -------------------------------------------------------------------------------- 1 |  2 | $ErrorActionPreference = 'Stop'; 3 | $toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" 4 | $packageName = $env:ChocolateyPackageName 5 | $ScriptToRun = "$toolsDir\Undo-WinRMConfig.ps1" 6 | 7 | $pp = Get-PackageParameters 8 | 9 | $RunImmediatelyValue = $False 10 | if ($pp.RunImmediately) { 11 | Write-Host "/RunImmediately was used, will run WinRM undo and exit..." 12 | Start-ChocolateyProcessAsAdmin "& `'$ScriptToRun`' -RunImmediately" 13 | } 14 | else 15 | { 16 | Start-ChocolateyProcessAsAdmin "& `'$ScriptToRun`'" 17 | } 18 | -------------------------------------------------------------------------------- /chocolateypackaging/tools/chocolateyuninstall.ps1: -------------------------------------------------------------------------------- 1 |  2 | $ErrorActionPreference = 'Stop'; 3 | $toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" 4 | $packageName = $env:ChocolateyPackageName 5 | $ScriptToRun = "$toolsDir\Undo-WinRMConfig.ps1" 6 | 7 | Start-ChocolateyProcessAsAdmin "& `'$ScriptToRun`' -RemoveShutdownScriptSetup" -------------------------------------------------------------------------------- /chocolateypackaging/undo-winrmconfig-during-shutdown.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | undo-winrmconfig-during-shutdown 6 | 1.2.0 7 | https://github.com/DarwinJS/CloudyWindowsAutomationCode/tree/master/Undo-WinRMConfig 8 | DarwinJS 9 | undo-winrmconfig-during-shutdown (Install) 10 | DarwinJS 11 | https://cloudywindows.io/winrm-for-provisioning---close-the-door-when-you-are-done-eh/ 12 | https://cdn.rawgit.com/DarwinJS/Undo-WinRMConfig/2fa5f0b4/chocolateypackaging/cloudywindows128.png 13 | false 14 | https://github.com/DarwinJS/Undo-WinRMConfig/blob/master/readme.md 15 | http://eepurl.com/cQbRwD 16 | https://github.com/DarwinJS/Undo-WinRMConfig/issues 17 | undo-winrmconfig-during-shutdown winrm packer admin 18 | Attempts to return WinRM to a pristine state after it has been used for system preparation (e.g. Packer) using a self-deleting computer shutdown script. 19 | Disable winrm through a self-deleting shutdown task. 20 | Many windows remote orchestration tools (e.g. Packer) instruct you to completely open up winrm permissions in a way that is not safe for production. 21 | Usually there is no built in method nor instruction on how to re-secure it or shut it back down. 22 | The assumption most likely being that you would handle proper winrm re-configuration as a part of production deployment. 23 | This is not a least privileged approach - depending on how big your company is and how widely your hypervisor templates are used - this is a disaster waiting to happen. So I feel leaving it in a disabled state by default is the far safer option. 24 | To complicate things, if you attempt to secure winrm or shut it down as your last step in orchestration you slam the door on the orchestration system and it marks the attempt as a failure. 25 | Due to imprecise timing, start up tasks that disable winrm could conflict with a subsequent attempt to re-enable it on the next boot for final configuration steps (especially if you are building a hypervisor template). 26 | This self-deleting shutdown task performs the disable on the first shutdown and deletes itself. 27 | If a system shutsdown extremely quickly there is some risk that the shutdown job would not be deleted - but in testing on AWS (very fast shutdown), there have not been an observed problems. 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | # Undo-WinRMConfig Documentation 3 | 4 | - [Undo-WinRMConfig Documentation](#undo-winrmconfig-documentation) 5 | - [Community Testing Help Needed!](#community-testing-help-needed) 6 | - [The Important Security Problem](#the-important-security-problem) 7 | - [This Solution](#this-solution) 8 | - [This Code Implementation](#this-code-implementation) 9 | - [The Disclaimers](#the-disclaimers) 10 | - [Ways to Run It](#ways-to-run-it) 11 | - [Direct Run From GitHub](#direct-run-from-github) 12 | - [Run Undo Process At Shutdown (default)](#run-undo-process-at-shutdown-default) 13 | - [Run Immediately (Careful!)](#run-immediately-careful) 14 | - [Remove Shutdown Job Before It Runs](#remove-shutdown-job-before-it-runs) 15 | - [Place On Image Template Without Running](#place-on-image-template-without-running) 16 | - [Chocolatey Package (Pre-release - does not show up publicly](#chocolatey-package-pre-release---does-not-show-up-publicly) 17 | - [Run At Shutdown (default)](#run-at-shutdown-default) 18 | - [Run Immediately (Careful!)](#run-immediately-careful) 19 | - [Remove Shutdown Job Before It Runs](#remove-shutdown-job-before-it-runs) 20 | # Community Testing Help Needed! 21 | It is not possible for me to test all OS versions and PowerShell versions running directly and via Chocolatey. Thinking community members could pick scenarios relevant to them. Below are some of the desirable tests. Problems reports should be submitted to: https://github.com/DarwinJS/CloudyWindowsAutomationCode/issues 22 | 23 | Tests for each below scenario: 24 | * "does it execute at all" but also 25 | * "does it effectively undo WinRM configuration (not disable)" and 26 | * "Can WinRm be rconfigured again with **conventional instructions** after this has run" 27 | 28 | Script Functionality: 29 | * (Default) Run and setup shutdown job (choco install) 30 | * Run immediately to Undo WinRM Configuration (don't run over remoting) (choco install -params '"/RunImmediately"' ) 31 | * -RemoveShutdownScriptConfig (Choco Uninstall) - removes shutdown job before it runs (it self deletes during actual operation) 32 | 33 | Run Scope: 34 | * Run Over Remoting (Choco / non-choco) 35 | * Run Under System Account (choco / non-choco) 36 | * Run under a system account service (choco / non-choco) 37 | 38 | OS / PowerShell Scope: 39 | * Windows 2008 R2 (Tested) / Windows 7 (Windows Version 6.1) 40 | * Server 2012 R2 (Tested) / Windows 8.1 (Windows Version 6.3) 41 | * Server 2016 (Tested) / Windows 10 (Windows Version 10.0) 42 | 43 | # The Important Security Problem 44 | Many windows remote orchestration tools (e.g. Packer) instruct you to open up winrm permissions in a way that is not safe for (nor intended for) use in production. (e.g. https://www.packer.io/docs/builders/ncloud.html#sample-code-of-template-json) Generally there is no guidance on how to re-secure it nor even a reminder to do so. The assumption most likely being that you would handle proper winrm re-configuration as a part of provisioning the machine - but in many organizations systems preparation may be the only use of WinRM - so it is forgotten. Or maybe whatever you use to re-configure it does not actively manage one of the permissive settings used during machine provisioning. 45 | 46 | Sysprep does not revert WinRM configuration to a pristine state and I checked with Microsoft and there is not an API call to revert to pristine either. 47 | 48 | Keep in mind that disabling WinRM is not the goal - but rather returning it to a pristine state (or as close as possible). This allows it to be reconfigured using conventional instructions - including the possibility that subsequent system preparation automation (like packer) will be used to prepare a new template image based on a previously prepared image template. 49 | 50 | Leaving WinRM in this state is not a least privileged approach for several reasons: 51 | 52 | - sysprep does not automatically deconfigure WinRM. 53 | - it is not secure at rest nor by default once booted. 54 | - it is unlikely the next user of the image template would think that WinRM has been preconfigured with permissive settings and that they would need to deal with it. 55 | - frequently images used for testing are not joined to a domain, so even if these settings are handled by a GPO in production environments - not all uses of the image template will necessarily have the benefit of such a GPO configuration. 56 | 57 | Depending on how big your company is and how widely your hypervisor templates are used - this is a disaster waiting to happen. So I feel leaving it in a disabled state by default is the far safer option. 58 | 59 | # This Solution 60 | This self-deleting shutdown task performs the disable on the first shutdown and deletes itself. It can also run immediately - which only works if you are not using WinRM to run it. 61 | 62 | # This Code Implementation 63 | The goal of this code is NOT to disable WinRM, but to set WinRM configuration back to as close to pristine as possible so that it can be reconfigured as necessary. 64 | At first glance, the code will appear a bit over complex, but that complexity has some rationale behind it: 65 | 1. If you attempt to revert WinRM configuration as your last step in automation that is using WinRM to access the machine - you slam the door on your own fingers and the automation will most likely exit with an error. This is the exact scenario for Packer. 66 | 2. Due to imprecise timing, **startup** tasks that disable winrm could conflict with a subsequent attempt to re-enable it on the next boot for final configuration steps. 67 | 3. Setting up a shutdown script requires some manipulation of GPO files and registry keys. To ensure appropriate security permissions no matter what user it used to execute this code, the setup is done via a scheduled job. 68 | 4. Since this implementation merely stages the undo to happen at shutdown - the code can run at any point during before the very last shutdown - it does not have to run last (though at the point you run it, you should not need anymore reboots with winrm enabled to finish configuration) 69 | 70 | If you have the luxury of running this code locally on the build machine without using WinRM, then you can use the "RunImmediately" switch to skip the above convolutions. 71 | 72 | FYI: If a system shuts down extremely quickly there is some risk that the shutdown job would not be deleted - but in testing on AWS (very fast shutdown), there have not been an observed problems. 73 | 74 | # The Disclaimers 75 | This code was engineered by reversing the commands required to configure winrm to be used for system preparation by Packer. In that regard it results in returning WinRM configuration to a state similar to, but quite possibly not identical to pristine defaults. 76 | 77 | If your WinRM configuration process involves configuring additional items, the reversal of those settings may need to be added to this script. You could create a customized copy or submit an issue or PR against this script. 78 | 79 | This code was engineered and tested on Server 2012 R2 / PowerShell 4 - it is unknown how well it works for earlier versions. 80 | # Ways to Run It 81 | 82 | ## Direct Run From GitHub 83 | 84 | ### Run Undo Process At Shutdown (default) 85 | Invoke-Expression (Invoke-WebRequest -UseBasicParsing -Uri 'https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/master/Undo-WinRMConfig.ps1') 86 | 87 | ### Run Immediately (Careful!) 88 | **Caution:** If you run this command while remoting in, you will slam the remoting connection closed and have a non-zero exit code - does not work with packer. 89 | 90 | Invoke-WebRequest -UseBasicParsing -Uri 'https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/master/Undo-WinRMConfig.ps1' -outfile $env:public\Undo-WinRMConfig.ps1 ; & $env:public\Undo-WinRMConfig.ps1 -RunImmediately 91 | 92 | ### Remove Shutdown Job Before It Runs 93 | 94 | Invoke-WebRequest -UseBasicParsing -Uri 'https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/master/Undo-WinRMConfig.ps1' -outfile $env:public\Undo-WinRMConfig.ps1 ; & $env:public\Undo-WinRMConfig.ps1 -RemoveShutdownScriptConfig 95 | 96 | ## Place On Image Template Without Running 97 | Invoke-WebRequest -UseBasicParsing -Uri 'https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/master/Undo-WinRMConfig.ps1' -outfile $env:public\Undo-WinRMConfig.ps1 98 | 99 | ## Chocolatey Package (Pre-release - does not show up publicly 100 | 101 | **ATTENTION: While this code is in the community feedback phase, I have it on a test feed. It will be available via chocolatey.org when the code is finalized** 102 | 103 | ### Run At Shutdown (default) 104 | choco install undo-winrmconfig-at-shutdown -pre -confirm 105 | 106 | ### Run Immediately (Careful!) 107 | **Caution:** If you run this command while remoting in, you will slam the remoting connection closed and have a non-zero exit code. 108 | 109 | choco install undo-winrmconfig-at-shutdown -pre -confirm -params '"/RunImmediately"' -source https://www.myget.org/F/chocotesting/api/v2/ 110 | 111 | ### Remove Shutdown Job Before It Runs 112 | 113 | choco uninstall undo-winrmconfig-at-shutdown -confirm 114 | 115 | --------------------------------------------------------------------------------