Create custom Windows Server images

Windows

You can create customized Windows Server images from existing Compute EngineWindows Server images. Use these custom images to create instances with bootdisks that are the same as your existing instances.

These custom images are useful for saving the operating system configuration ofyour existing instances and reusing the same configuration to create otherinstances.

The following tasks are not covered in this section:

Before you begin

Prepare to create a Windows Server image

Before you create the image, runGCESysprep on the instance to prepare it forthe image creation process.

GCESysprep prepares an instance for becoming a Compute Engine image bycompleting the following steps:

  1. Disables theGCEStartup scheduled task.
  2. Deletes all files from temp folder location.
  3. Clears all Windows event logs.
  4. Runs sysprep.exe /generalize /oobe /quit /unattend
  5. Configuresinstance_setup.ps1 to run on the first boot of the VM instance.
  6. Deletes the RDP Certificate.
  7. Removes the stored list of persistent disks.
  8. Enables RDP and WinRM firewall rules.
  9. Disables the Google OS Config service.
  10. Shuts down the instance.

GCESysprep operations are logged to the Windows event log and serial port 1.Sysprep writes to multiplelog files.

Note: Sysprep onlyclears the built-in Administrator account's passwordfor Windows server editions. We encourage users to review and update all localaccounts prior to runningGCESysprep as any enabled accounts and credentialswill be present in the new image.

How to create a Compute Engine image usingGCESysprep:

  1. RunGCESysprep with administrative rights.

    GCESysprep
  2. Create the image.

Specify an image location

When creating a custom image, you can specify the image'sCloud Storage location, excludingdual-region locations. By specifying the image storage location, youcan meet your regulatory and compliance requirements for data locality as wellas your high availability needs by ensuring redundancy across regions.

The storage location feature is optional. If you don't select a location,Compute Engine will store your image in the multi-region closest to theimage source. You can create custom images from source disks, images, snapshots,or images stored in Cloud Storage. You can use these images to createnew VM instances.

All of your existing images prior to this feature launch remain where they are.The only change is that you can view the image location of all your images.If you have an existing image you want to move, you must recreate it in theselected location.

Create a Windows image

You can create disk images from the following sources:

  • A persistent disk, even while that disk is attached to an instance
  • A snapshot of a persistent disk
  • Another image in your project
  • An image that is shared from another project
  • Animported imagestored in Cloud Storage

Console

  1. In the Google Cloud console, go to theCreate a new image page.

    Create a new image

  2. Specify the imageName.
  3. Choose aSource disk with a Windows operating system from which youwant to create an image.
  4. Specify theLocation to store the image. Choose an imagelocation from theBased on source disk location (default)drop-down menu. For example, specifyus to store the image in theusmulti-region, orus-central1 to store it in theus-central1 region.If you don't make a selection, Compute Engine will store theimage in the multi-region closest to your image's source location.
  5. Specify the properties for your image. For example, you canspecify an image family name for your image to organize this image aspart of animage family.
  6. ClickCreate.

gcloud

Use thegcloud compute withimages create, and providethe source persistent disk from which you want to create an image.Optionally, include the--force flag to create the image even if it isattached to a running instance.

gcloud compute images create example-image --source-diskDISK_NAME \    --source-disk-zoneZONE \    --storage-locationLOCATION \    [--force]

Replace the following:

  • DISK_NAME: the name of the source disk to create the image from.
  • ZONE: the zone of the disk.
  • LOCATION: an optional flag that lets you designate theregion or multi-region where your image is going to be stored.For example, specifyus to store the image in theusmulti-region, orus-central1 to store it in theus-central1 region.If you don't make a selection, Compute Engine stores theimage in the multi-region closest to your image's source location.
  • --force: an optional flag that creates the image even if the disk isattached to a running instance. This option mightcompromise the integrity of your image. Stop the instance before youcreate the image if possible.

When you run this command,gcloud compute creates a new image based onthe persistent disk you provided and adds it to your collection. You canconfirm that your image was successfully created by running:

gcloud compute images list

Go

Before trying this sample, follow theGo setup instructions in theCompute Engine quickstart using client libraries. For more information, see theCompute EngineGo API reference documentation.

To authenticate to Compute Engine, set up Application Default Credentials. For more information, seeSet up authentication for a local development environment.

import("context""fmt""io""strings"compute"cloud.google.com/go/compute/apiv1"computepb"cloud.google.com/go/compute/apiv1/computepb""google.golang.org/protobuf/proto")// createWindowsOSImage creates a new Windows image from the specified source disk.funccreateWindowsOSImage(wio.Writer,projectID,zone,sourceDiskName,imageName,storageLocationstring,forceCreatebool,)error{// projectID := "your_project_id"// zone := "europe-central2-b"// sourceDiskName := "your_source_disk_name"// imageName := "your_image_name"// storageLocation := "eu"// forceCreate := falsectx:=context.Background()instancesClient,err:=compute.NewInstancesRESTClient(ctx)iferr!=nil{returnfmt.Errorf("NewInstancesRESTClient: %w",err)}deferinstancesClient.Close()imagesClient,err:=compute.NewImagesRESTClient(ctx)iferr!=nil{returnfmt.Errorf("NewImagesRESTClient: %w",err)}deferimagesClient.Close()disksClient,err:=compute.NewDisksRESTClient(ctx)iferr!=nil{returnfmt.Errorf("NewDisksRESTClient: %w",err)}deferdisksClient.Close()// Getting instances where source disk is attacheddiskRequest:=&computepb.GetDiskRequest{Project:projectID,Zone:zone,Disk:sourceDiskName,}sourceDisk,err:=disksClient.Get(ctx,diskRequest)iferr!=nil{returnfmt.Errorf("unable to get disk: %w",err)}// Сhecking whether the instances is stoppedfor_,fullInstanceName:=rangesourceDisk.GetUsers(){parsedName:=strings.Split(fullInstanceName,"/")l:=len(parsedName)ifl <5{returnfmt.Errorf("API returned instance name with unexpected format",)}instanceReq:=&computepb.GetInstanceRequest{Project:parsedName[l-5],Zone:parsedName[l-3],Instance:parsedName[l-1],}instance,err:=instancesClient.Get(ctx,instanceReq)iferr!=nil{returnfmt.Errorf("unable to get instance: %w",err)}ifinstance.GetStatus()!="TERMINATED" &&instance.GetStatus()!="STOPPED"{if!forceCreate{returnfmt.Errorf("instance %s should be stopped. "+"Please stop the instance using "+"GCESysprep command or set forceCreate parameter to true "+"(not recommended). More information here: "+"https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image#api",parsedName[l-1],)}}}ifforceCreate{fmt.Fprintf(w,"Warning: ForceCreate option compromise the integrity of your image. "+"Stop the instance before you create the image if possible.",)}req:=&computepb.InsertImageRequest{Project:projectID,ForceCreate:&forceCreate,ImageResource:&computepb.Image{Name:proto.String(imageName),SourceDisk:proto.String(fmt.Sprintf("zones/%s/disks/%s",zone,sourceDiskName)),StorageLocations:[]string{storageLocation},},}op,err:=imagesClient.Insert(ctx,req)iferr!=nil{returnfmt.Errorf("unable to create image: %w",err)}iferr=op.Wait(ctx);err!=nil{returnfmt.Errorf("unable to wait for the operation: %w",err)}fmt.Fprintf(w,"Image created\n")returnnil}

Java

Before trying this sample, follow theJava setup instructions in theCompute Engine quickstart using client libraries. For more information, see theCompute EngineJava API reference documentation.

To authenticate to Compute Engine, set up Application Default Credentials. For more information, seeSet up authentication for a local development environment.

importcom.google.cloud.compute.v1.Disk;importcom.google.cloud.compute.v1.DisksClient;importcom.google.cloud.compute.v1.Image;importcom.google.cloud.compute.v1.ImagesClient;importcom.google.cloud.compute.v1.InsertImageRequest;importcom.google.cloud.compute.v1.Instance;importcom.google.cloud.compute.v1.InstancesClient;importcom.google.cloud.compute.v1.Operation;importjava.io.IOException;importjava.util.Arrays;importjava.util.HashMap;importjava.util.Map;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.TimeoutException;publicclassCreateImage{publicstaticvoidmain(String[]args)throwsIOException,ExecutionException,InterruptedException,TimeoutException{// TODO(developer): Replace these variables before running the sample.// Project ID or project number of the Cloud project you use.Stringproject="your-project-id";// Zone of the disk you copy from.Stringzone="europe-central2-b";// Name of the source disk you copy from.StringsourceDiskName="source-disk-name";// Name of the image you want to create.StringimageName="your-image-name";// Storage location for the image. If the value is undefined,// function will store the image in the multi-region closest to your image's source location.StringstorageLocation="eu";// Create the image even if the source disk is attached to a running instance.booleanforceCreate=false;createImage(project,zone,sourceDiskName,imageName,storageLocation,forceCreate);}// Creates a new disk image from the specified source disk.publicstaticvoidcreateImage(Stringproject,Stringzone,StringsourceDiskName,StringimageName,StringstorageLocation,booleanforceCreate)throwsIOException,ExecutionException,InterruptedException,TimeoutException{// Initialize client that will be used to send requests. This client only needs to be created// once, and can be reused for multiple requests. After completing all of your requests, call// the `client.close()` method on the client to safely// clean up any remaining background resources.try(ImagesClientimagesClient=ImagesClient.create();InstancesClientinstancesClient=InstancesClient.create();DisksClientdisksClient=DisksClient.create()){Diskdisk=disksClient.get(project,zone,sourceDiskName);// Getting instances where source disk is attached.for(StringfullInstanceName:disk.getUsersList()){Map<String,String>instanceInfo=parseInstanceName(fullInstanceName);Instanceinstance=instancesClient.get(instanceInfo.get("instanceProjectId"),instanceInfo.get("instanceZone"),instanceInfo.get("instanceName"));// Сheck whether the instances are stopped.if(!Arrays.asList("TERMINATED","STOPPED").contains(instance.getStatus())            &&!forceCreate){thrownewIllegalStateException(String.format("Instance %s should be stopped. For Windows instances please stop the instance "+"using GCESysprep command. For Linux instances just shut it down normally."+" You can suppress this error and create an image of the disk by setting "+"'forceCreate' parameter to true (not recommended). "+"More information here: "+"* https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image#api"+"* https://cloud.google.com/compute/docs/images/create-delete-deprecate-private-images#prepare_instance_for_image",instanceInfo.get("instanceName")));}}if(forceCreate){System.out.println("Warning: forceCreate option compromise the integrity of your image. "+"Stop the instance before you create the image if possible.");}// Create Image.IImageimage=IImagenewBuilder().setName(imageName).setSourceDisk(String.format("/zones/%s/disks/%s",zone,sourceDiskName)).addStorageLocations(storageLocation.isEmpty()?"":storageLocation).build();IInsertImageRequestinsertImageRequest=IInsertImageRequestnewBuilder().setProject(project).ssetForceCreateforceCreate).setImageResource(image).build();OOperationresponse=imagesClient.insertAsync(insertImageRequest).get(5,TimeUnit.MINUTES);if(rresponse.hasError(){System.out.println("Image creation failed ! ! "+response);return;}System.out.println("Image created.");}}publicstaticMap<String,String>parseInstanceName(Stringname){String[]parsedName=name.split("/");intsplitLength=parsedName.length;if(splitLength <5){thrownewIllegalArgumentException("Provide correct instance name in the following format: "+"https://www.googleapis.com/compute/v1/projects/PROJECT/zones/ZONE/instances/INSTANCE_NAME");}returnnewHashMap<>(){{put("instanceName",parsedName[splitLength-1]);put("instanceZone",parsedName[splitLength-3]);put("instanceProjectId",parsedName[splitLength-5]);}};}}

Node.js

Node.js

Before trying this sample, follow theNode.js setup instructions in theCompute Engine quickstart using client libraries. For more information, see theCompute EngineNode.js API reference documentation.

To authenticate to Compute Engine, set up Application Default Credentials. For more information, seeSet up authentication for a local development environment.

/** * TODO(developer): Uncomment and replace these variables before running the sample. */// const projectId = 'YOUR_PROJECT_ID';// const zone = 'europe-central2-b';// const sourceDiskName = 'YOUR_SOURCE_DISK_NAME';// const imageName = 'YOUR_IMAGE_NAME';// const storageLocation = 'eu';// const forceCreate = false;constcompute=require('@google-cloud/compute');functionparseInstanceName(name){constparsedName=name.split('/');constl=parsedName.length;if(parsedName.legth <5){thrownewError('Provide correct instance name in the following format: https://www.googleapis.com/compute/v1/projects/PROJECT/zones/ZONE/instances/INSTANCE_NAME');}return[parsedName[l-1],parsedName[l-3],parsedName[l-5]];}asyncfunctioncreateWindowsOSImage(){constimagesClient=newcompute.ImagesClient();constinstancesClient=newcompute.InstancesClient();constdisksClient=newcompute.DisksClient();// Getting instances where source disk is attachedconst[sourceDisk]=awaitdisksClient.get({project:projectId,zone,disk:sourceDiskName,});// Сhecking whether the instances is stoppedfor(constfullInstanceNameofsourceDisk.users){const[instanceName,instanceZone,instanceProjectId]=parseInstanceName(fullInstanceName);const[instance]=awaitinstancesClient.get({project:instanceProjectId,zone:instanceZone,instance:instanceName,});if(!['TERMINATED','STOPPED'].includes(instance.status)&&!forceCreate){thrownewError(`Instance${instanceName} should be stopped. Please stop the instance using GCESysprep command or set forceCreate parameter to true (not recommended). More information here: https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image#api.`);}}if(forceCreate){console.warn('Warning: forceCreate option compromise the integrity of your image. Stop the instance before you create the image if possible.');}const[response]=awaitimagesClient.insert({project:projectId,forceCreate,imageResource:{name:imageName,sourceDisk:`/zones/${zone}/disks/${sourceDiskName}`,storageLocations:storageLocation?[storageLocation]:[],},});letoperation=response.latestResponse;constoperationsClient=newccompute.GlobalOperationsClient);// Wait for the create operation to complete.while(operation.status!=='DONE'){[operation]=awaitoperationsClient.wait({operation:operation.name,project:projectId,});}console.log('Image created.');}createWindowsOSImage();

Python

Python

Before trying this sample, follow thePython setup instructions in theCompute Engine quickstart using client libraries. For more information, see theCompute EnginePython API reference documentation.

To authenticate to Compute Engine, set up Application Default Credentials. For more information, seeSet up authentication for a local development environment.

from__future__importannotationsimportsysfromtypingimportAnyimportwarningsfromgoogle.api_core.extended_operationimportExtendedOperationfromgoogle.cloudimportcompute_v1defwait_for_extended_operation(operation:ExtendedOperation,verbose_name:str="operation",timeout:int=300)->Any:"""    Waits for the extended (long-running) operation to complete.    If the operation is successful, it will return its result.    If the operation ends with an error, an exception will be raised.    If there were any warnings during the execution of the operation    they will be printed to sys.stderr.    Args:        operation: a long-running operation you want to wait on.        verbose_name: (optional) a more verbose name of the operation,            used only during error and warning reporting.        timeout: how long (in seconds) to wait for operation to finish.            If None, wait indefinitely.    Returns:        Whatever the operation.result() returns.    Raises:        This method will raise the exception received from `operation.exception()`        or RuntimeError if there is no exception set, but there is an `error_code`        set for the `operation`.        In case of an operation taking longer than `timeout` seconds to complete,        a `concurrent.futures.TimeoutError` will be raised.    """result=operation.result(timeout=timeout)ifoperation.error_code:print(f"Error during{verbose_name}: [Code:{operation.error_code}]:{operation.error_message}",file=sys.stderr,flush=True,)print(f"Operation ID:{operation.name}",file=sys.stderr,flush=True)raiseoperation.exception()orRuntimeError(operation.error_message)ifoperation.warnings:print(f"Warnings during{verbose_name}:\n",file=sys.stderr,flush=True)forwarninginoperation.warnings:print(f" -{warning.code}:{warning.message}",file=sys.stderr,flush=True)returnresultSTOPPED_MACHINE_STATUS=(compute_v1.Instance.Status.TERMINATED.name,compute_v1.Instance.Status.STOPPED.name,)defcreate_image_from_disk(project_id:str,zone:str,source_disk_name:str,image_name:str,storage_location:str|None=None,force_create:bool=False,)->compute_v1.Image:"""    Creates a new disk image.    Args:        project_id: project ID or project number of the Cloud project you use.        zone: zone of the disk you copy from.        source_disk_name: name of the source disk you copy from.        image_name: name of the image you want to create.        storage_location: storage location for the image. If the value is undefined,            function will store the image in the multi-region closest to your image's            source location.        force_create: create the image even if the source disk is attached to a            running instance.    Returns:        An Image object.    """image_client=compute_v1.ImagesClient()disk_client=compute_v1.DisksClient()instance_client=compute_v1.InstancesClient()# Get source diskdisk=disk_client.get(project=project_id,zone=zone,disk=source_disk_name)fordisk_userindisk.users:instance_name=disk_user.split("/")[-1]instance=instance_client.get(project=project_id,zone=zone,instance=instance_name)ifinstance.statusinSTOPPED_MACHINE_STATUS:continueifnotforce_create:raiseRuntimeError(f"Instance{disk_user} should be stopped. For Windows instances please "f"stop the instance using `GCESysprep` command. For Linux instances just "f"shut it down normally. You can supress this error and create an image of"f"the disk by setting `force_create` parameter to true (not recommended).\n"f"More information here:\n"f" * https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image#api\n"f" * https://cloud.google.com/compute/docs/images/create-delete-deprecate-private-images#prepare_instance_for_image")else:warnings.warn(f"Warning: The `force_create` option may compromise the integrity of your image. "f"Stop the{disk_user} instance before you create the image if possible.")# Create imageimage=compute_v1.Image()image.source_disk=disk.self_linkimage.name=image_nameifstorage_location:image.storage_locations=[storage_location]operation=image_client.insert(project=project_id,image_resource=image)wait_for_extended_operation(operation,"image creation from disk")returnimage_client.get(project=project_id,image=image_name)

REST

Make aPOST request to theimages().insertmethod, with asourceDisk URL in the request body.

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/images?FORCE_OPTION{  "name": "IMAGE_NAME",  "sourceDisk": "zones/ZONE/disks/DISK_NAME",  "storageLocations": "LOCATION",}

Replace the following:

  • PROJECT_ID: the project ID for this request.
  • FORCE_OPTION: an optional flag to create the image even if the sourcedisk is attached to a running instance. SpecifyforceCreate=trueat the end of your POST line to set this option. This option mightcompromise the integrity of your image. Stop the instance before youcreate the image if possible.
  • IMAGE_NAME: the name to give this image.
  • ZONE: the zone of the source disk to create an image from.
  • DISK_NAME: the name of the source disk.
  • LOCATION: an optional parameter that lets you selectthe multi-region or a region storage location of your image.For example, specifyus to store the image in theusmulti-region, orus-central1 to store it in theus-central1 region.If you don't make a selection, Compute Engine stores theimage in the multi-region closest to your image's source location.

For more information about adding images, see theimages reference.

Update Windows agents and scripts

Compute Engine occasionally releases new Windows images with thelatest agents and scripts. These items assist Windows instances with startupand shutdown processes, account management, and address management.

Since Windows image versionv20160112, the Windows agent updates itself withupstream releases. You can disable these agent updates by setting thedisable-agent-updates instance metadata key totrue. If you have instancesthat are based on older image releases, you canmanually update the Windows agent of those instances.

What's next

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-15 UTC.