Skip to content

Instantly share code, notes, and snippets.

@marsell
Created October 24, 2018 20:15
Show Gist options
  • Save marsell/dac4771a6a313e404258112c09687db3 to your computer and use it in GitHub Desktop.
Save marsell/dac4771a6a313e404258112c09687db3 to your computer and use it in GitHub Desktop.
{"set_internal_metadata":{"operator-script":"# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this\n# file, You can obtain one at http://mozilla.org/MPL/2.0/.\n#\n# Copyright (c) 2018, Joyent, Inc.\n#\n# Set Window's cleanmgr to (nearly) max, and run it. This cleans up most\n# temporary (files, cache) and unneeded data (outdated installation data).\n#\n# In order for this script to work, a Windows image needs to have mdata-get.exe,\n# mdata-put.exe and prepare_image_runner.ps1 installed in C:\\smartdc\\bin, and\n# prepare_image_runner.ps1 should be run by Windows on every boot. Upon boot,\n# prepare_image_runner.ps1 will then check if \"sdc:operator-script\" metadata\n# (seen as internal_metadata.\"operator-script\" in \"vmadm get\" output) is present\n# over COM2, and run it. If it's not present, booting continues as normal.\n#\n# Apparently, the only way to get cleanmgr to run without displaying a final\n# information dialog -- thus hanging image creation -- is through the /autoclean\n# flag. We abuse this by setting all available cleanup options in the registry\n# to be run by autoclean. Since the VM will be rolled back after image creation,\n# this change is not a problem.\n#\n# There are also a couple very expensive cleanmgr checks that increase\n# cleanmgr's run time up to 5x, which we cannot afford with the 5m time limit\n# imposed on image creation between prepare-script 'running' and\n# final 'error'/'success' calls. The only way to disable these checks outright\n# is to temporarily move their registry keys, which we do as well.\n#\n# After that, cleanmgr is run, then moving the expensive registry keys back.\n#\n# Unfortunately, cleanmgr /autoclean appears to contain its own logic about when\n# it will clean up something. As a result, we also empty recycle bins and clear\n# most temp and log directories manually.\n\n$parent_path = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VolumeCaches'\n$tmp_parent_path = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer'\n$expensive_cleanups = 'Update Cleanup', 'System error memory dump files'\n$clean_dirs = 'c:\\Windows\\Temp\\*', 'c:\\Windows\\Logs\\*', 'c:\\Windows\\Minidump\\*',\n 'C:\\PerfLogs\\*', 'C:\\Windows\\Downloaded Program Files\\*',\n 'C:\\Windows\\*.log', 'C:\\Users\\*\\AppData\\Local\\Temp\\*'\n\n\nfunction mput($key, $val) {\n c:\\smartdc\\bin\\mdata-put.exe prepare-image:$key $val\n}\n\nfunction setting_path($id) {\n \"$parent_path\\$id\"\n}\n\nfunction tmp_path($id) {\n \"$tmp_parent_path\\$id\"\n}\n\nfunction error($msg) {\n echo \"ERROR\"\n echo $msg\n mput 'state' 'error'\n mput 'error' $msg\n exit\n}\n\n\necho 'Starting run...'\nmput 'state' 'running'\n\necho \"Disabling particularly expensive cleanmgr operations\"\nforeach ($cleanup in $expensive_cleanups) {\n try {\n Move-Item -LiteralPath (setting_path $cleanup) `\n -Destination (tmp_path $cleanup) -ErrorAction Stop\n } catch [System.Management.Automation.PSInvalidOperationException] {}\n}\n\necho 'Marking all other checks for /autoclean'\ntry {\n $cleanups = (Get-Item -LiteralPath $parent_path).GetSubKeyNames()\n} catch {\n error 'Unknown hive'\n}\n\n$add_auto_paths = @()\ntry {\n foreach ($cleanup in $cleanups) {\n $path = setting_path $cleanup\n $node = Get-Item -LiteralPath $path\n if ($node.GetValue('Autorun') -ne 1) {\n $add_auto_paths = $add_auto_paths + $path\n }\n }\n} catch {\n error 'Bad Get-Item'\n}\n\ntry {\n foreach ($path in $add_auto_paths) {\n Set-ItemProperty -LiteralPath $path -Name 'Autorun' `\n -Type Dword -Value 1 -ErrorAction Stop\n }\n} catch {\n error 'Bad Set-Item'\n}\n\necho 'Running cleanmgr...'\ntry {\n # Out-Null needed to block script until cleanmgr completes\n c:\\windows\\system32\\cleanmgr.exe /autoclean | Out-Null\n} catch [System.Management.Automation.CommandNotFoundException] {\n # Ignore, in case we are dealing with a 2012r2 instance without\n # Desktop Experience installed\n} catch {\n error 'Bad cleanmgr'\n}\n\necho 'Unmarking other checks /autoclean'\ntry {\n foreach ($path in $add_auto_paths) {\n Set-ItemProperty -LiteralPath $path -Name 'Autorun' `\n -Type Dword -Value 0 -ErrorAction Stop\n }\n} catch {\n error 'Bad auto undo'\n}\n\necho 'Reenabling expensive cleanmgr operations'\nforeach ($cleanup in $expensive_cleanups) {\n try {\n Move-Item -LiteralPath (tmp_path $cleanup) `\n -Destination (setting_path $cleanup) -ErrorAction Stop\n } catch [System.Management.Automation.PSInvalidOperationException] {}\n}\n\necho 'Empty Recycle Bins'\ntry {\n Clear-RecycleBin -Confirm:$false -ErrorAction Stop\n} catch [System.ComponentModel.Win32Exception],\n [System.Management.Automation.CommandNotFoundException] {\n # Ignore, in case we are dealing with a Powershell older than 5.1 on 2012r2.\n # By default, 2012r2 has Powershell 4.0, but updates can increase it to 5.1\n} catch {\n error 'Bad empty recycle'\n}\n\necho 'Clear out temp and log directories'\nforeach ($path in $clean_dirs) {\n try {\n Remove-Item -Path $path -Recurse -Force -ErrorAction Stop\n } catch {}\n}\n\n\nmput 'state' 'success'\necho 'Done!'\n"}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment