diff --git a/image_creator/os_type/windows/__init__.py b/image_creator/os_type/windows/__init__.py index b6f06fbfe3624de8276687e605528252ef402db1..bc99c6259595d61f5e535630df0d7e91c5057307 100644 --- a/image_creator/os_type/windows/__init__.py +++ b/image_creator/os_type/windows/__init__.py @@ -132,23 +132,20 @@ class Windows(OSBase): device = self.image.g.part_to_dev(self.root) self.last_part_num = self.image.g.part_list(device)[-1]['part_num'] - self.last_drive = None - self.system_drive = None - - for drive, part in self.image.g.inspect_get_drive_mappings(self.root): - if part == "%s%d" % (device, self.last_part_num): - self.last_drive = drive - if part == self.root: - self.system_drive = drive - - assert self.system_drive self.product_name = self.image.g.inspect_get_product_name(self.root) self.vm = VM(self.image.device, self.sysprep_params) self.registry = Registry(self.image.g, self.root) - self.syspreped = False + # If the image is already sysprepped we cannot further customize it + self.mount(readonly=True) + try: + self.out.output("Checking if media is sysprepped ...", False) + self.syspreped = self.registry.get_setup_state() > 0 + self.out.success("done") + finally: + self.umount() @sysprep('Disabling IPv6 privacy extensions') def disable_ipv6_privacy_extensions(self): @@ -303,7 +300,7 @@ class Windows(OSBase): if self.syspreped: raise FatalError( - "Microsoft's System Preparation Tool has ran on the Image." + "Microsoft's System Preparation Tool has ran on the Image. " "Further image customization is not possible.") txt = "System preparation parameter: `%s' is needed but missing!" diff --git a/image_creator/os_type/windows/registry.py b/image_creator/os_type/windows/registry.py index e717b50524e1c430d267faa2a28ec63aef17c2ee..acdc71fe81707384f9b443cbb16a88bad1f14b36 100644 --- a/image_creator/os_type/windows/registry.py +++ b/image_creator/os_type/windows/registry.py @@ -24,6 +24,15 @@ import tempfile import os import struct +# http://technet.microsoft.com/en-us/library/hh824815.aspx +WINDOWS_SETUP_STATES = ( + "IMAGE_STATE_COMPLETE", + "IMAGE_STATE_UNDEPLOYABLE", + "IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE", + "IMAGE_STATE_GENERALIZE_RESEAL_TO_AUDIT", + "IMAGE_STATE_SPECIALIZE_RESEAL_TO_OOBE", + "IMAGE_STATE_SPECIALIZE_RESEAL_TO_AUDIT") + class Registry(object): """Windows Registry manipulation methods""" @@ -70,6 +79,41 @@ class Registry(object): return OpenHive() + def get_setup_state(self): + """Returns the stage of Windows Setup the image is in. + The method will return an int with one of the following values: + 0 => IMAGE_STATE_COMPLETE + 1 => IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE + 2 => IMAGE_STATE_GENERALIZE_RESEAL_TO_AUDIT + 3 => IMAGE_STATE_SPECIALIZE_RESEAL_TO_OOBE + 4 => IMAGE_STATE_SPECIALIZE_RESEAL_TO_AUDIT + For more information check here: + http://technet.microsoft.com/en-us/library/hh824815.aspx + """ + + with self.open_hive('SOFTWARE') as hive: + # Navigate to: + # SOFTWARE/Microsoft/Windows/CurrentVersion/Setup/State + state = hive.root() + for child in ('Microsoft', 'Windows', 'CurrentVersion', + 'Setup', 'State'): + state = hive.node_get_child(state, child) + + image_state = hive.node_get_value(state, 'ImageState') + vtype, value = hive.value_value(image_state) + assert vtype == 1L, \ + "ImageState field type (=%d) is not REG_SZ" % vtype + + value = value.decode('utf-16le') + + ret = 0 + for known_state in WINDOWS_SETUP_STATES: + if value == known_state + '\x00': # REG_SZ is null-terminated + return ret + ret += 1 + + raise FatalError("Unknown Windows Setup State: %s" % value) + def runonce(self, commands): """Add commands to the RunOnce registry key"""