<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Creating a backup of map incl. feature layers, visualization and attachments in ArcGIS Online Questions</title>
    <link>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615462#M64767</link>
    <description>&lt;P&gt;Hi! I made two different scripts meant to be used as toolboxes in ArcGIS Pro inspired by your approach named "ExportBackup" and "RestoreMap":&lt;BR /&gt;&lt;BR /&gt;1. Find the map in AGOL you want to create a complete backup from and open it in ArcGIS Pro.&lt;BR /&gt;&lt;BR /&gt;2. Run this script which loops through every layer except basemaps, WMS etc. and saves them as individual .gdb (with attachments) and .lyrx (keeps symobology):&lt;BR /&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;import arcpy
import os
import csv
import re

# Get output folder from script tool parameter
output_folder = arcpy.GetParameterAsText(0)

# Prepare log
log_file_path = os.path.join(output_folder, "layer_export_log.csv")
log_rows = [["Original Layer Name", "Sanitized Name", "GDB Path", "Attachments Exported", "Symbology File"]]

# Helper to sanitize names
def sanitize_name(name):
    return re.sub(r'[^a-zA-Z0-9_]', '_', name)[:50]

# Get current ArcGIS Pro project and active map
project = arcpy.mp.ArcGISProject("CURRENT")
map_obj = project.activeMap

# Loop through all layers
for lyr in map_obj.listLayers():
    # Skip group layers, basemaps, or unsupported types
    if lyr.isGroupLayer or lyr.isBasemapLayer or not lyr.isFeatureLayer:
        try:
            arcpy.AddMessage(f"&lt;span class="lia-unicode-emoji" title=":next_track_button:"&gt;⏭&lt;/span&gt;️ Skipping: {lyr.name}")
        except:
            arcpy.AddMessage("&lt;span class="lia-unicode-emoji" title=":next_track_button:"&gt;⏭&lt;/span&gt;️ Skipping unsupported or service-based layer")
        continue

    # Try to access the layer name safely
    try:
        original_name = lyr.name
    except:
        original_name = "Unnamed_Layer"

    layer_name = sanitize_name(original_name)
    gdb_path = os.path.join(output_folder, f"{layer_name}.gdb")
    lyrx_path = os.path.join(output_folder, f"{layer_name}.lyrx")
    attachments_exported = "Included in GDB"

    arcpy.AddMessage(f"\n&lt;span class="lia-unicode-emoji" title=":counterclockwise_arrows_button:"&gt;🔄&lt;/span&gt; Exporting: {original_name} → {layer_name}")

    # Create File GDB
    if not arcpy.Exists(gdb_path):
        arcpy.management.CreateFileGDB(output_folder, f"{layer_name}.gdb")

    out_feature = os.path.join(gdb_path, layer_name)

    try:
        # Export feature class
        arcpy.conversion.FeatureClassToFeatureClass(
            in_features=lyr,
            out_path=gdb_path,
            out_name=layer_name
        )
        arcpy.AddMessage("&lt;span class="lia-unicode-emoji" title=":paperclip:"&gt;📎&lt;/span&gt; Attachments preserved within File Geodatabase.")

        # Temporarily add exported data to map
        temp_layer = map_obj.addDataFromPath(out_feature)

        # Copy symbology from original layer
        try:
            temp_layer.symbology = lyr.symbology
            arcpy.AddMessage(":artist_palette:&lt;/img&gt; Symbology copied from original layer.")
        except Exception as e:
            arcpy.AddWarning(f":warning:&lt;/img&gt; Could not copy symbology: {str(e)}")

        # Save styled layer to .lyrx
        temp_layer.saveACopy(lyrx_path)
        arcpy.AddMessage(f":floppy_disk:&lt;/img&gt; Symbology saved to: {lyrx_path}")

        # Clean up
        map_obj.removeLayer(temp_layer)

    except Exception as e:
        arcpy.AddWarning(f"&lt;span class="lia-unicode-emoji" title=":cross_mark:"&gt;❌&lt;/span&gt; Failed to export {original_name}: {str(e)}")
        continue

    # Log export result
    log_rows.append([original_name, layer_name, gdb_path, attachments_exported, lyrx_path])

# Write CSV log
with open(log_file_path, mode="w", newline='', encoding="utf-8") as log_file:
    writer = csv.writer(log_file)
    writer.writerows(log_rows)

arcpy.AddMessage(f"\n&lt;span class="lia-unicode-emoji" title=":memo:"&gt;📝&lt;/span&gt; Log file saved to: {log_file_path}")
arcpy.AddMessage("&lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Done! All eligible layers exported.")&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;3. Run this script to restore the map just like it was:&lt;/P&gt;&lt;LI-CODE lang="python"&gt;import arcpy
import os

# Folder containing .gdb and matching .lyrx files
input_folder = arcpy.GetParameterAsText(0)
project = arcpy.mp.ArcGISProject("CURRENT")
map_obj = project.activeMap

arcpy.AddMessage(f":open_file_folder:&lt;/img&gt; Restoring from: {input_folder}")

for item in os.listdir(input_folder):
    if item.lower().endswith(".gdb"):
        layer_name = os.path.splitext(item)[0]
        gdb_path = os.path.join(input_folder, item)
        lyrx_path = os.path.join(input_folder, f"{layer_name}.lyrx")

        arcpy.env.workspace = gdb_path
        feature_classes = arcpy.ListFeatureClasses()
        if not feature_classes:
            arcpy.AddWarning(f":warning:&lt;/img&gt; No feature classes in {gdb_path}.")
            continue

        fc_path = os.path.join(gdb_path, feature_classes[0])
        arcpy.AddMessage(f"&lt;span class="lia-unicode-emoji" title=":heavy_plus_sign:"&gt;➕&lt;/span&gt; Adding: {layer_name}")

        try:
            new_layer = map_obj.addDataFromPath(fc_path)

            if os.path.exists(lyrx_path):
                try:
                    sym_layer_file = arcpy.mp.LayerFile(lyrx_path)
                    sym_layer = sym_layer_file.listLayers()[0]
                    new_layer.symbology = sym_layer.symbology
                    arcpy.AddMessage(f":artist_palette:&lt;/img&gt; Symbology copied from: {lyrx_path}")
                except Exception as e:
                    arcpy.AddWarning(f":warning:&lt;/img&gt; Failed to copy symbology: {str(e)}")
            else:
                arcpy.AddWarning(f":artist_palette:&lt;/img&gt; No .lyrx found for: {layer_name}")
        except Exception as e:
            arcpy.AddWarning(f"&lt;span class="lia-unicode-emoji" title=":cross_mark:"&gt;❌&lt;/span&gt; Failed to load {layer_name}: {str(e)}")

arcpy.AddMessage("&lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Done restoring layers.")&lt;/LI-CODE&gt;&lt;P&gt;&lt;BR /&gt;Both toolboxes has to be set up with a mandatory output folder for the "ExportBackup" and input folder for "RestoreMap". Works like a charm!&lt;/P&gt;</description>
    <pubDate>Fri, 16 May 2025 14:36:22 GMT</pubDate>
    <dc:creator>ErikAIversen</dc:creator>
    <dc:date>2025-05-16T14:36:22Z</dc:date>
    <item>
      <title>Creating a backup of map incl. feature layers, visualization and attachments</title>
      <link>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615368#M64760</link>
      <description>&lt;P&gt;Over time the company I work for has built up a lot of maps in online that are no longer in active use.&amp;nbsp;All these maps and feature layers contribute to credit usage, but we have kept them online since we sometimes have to revisit old maps for new projects with returning clients.&amp;nbsp;&amp;nbsp;&lt;BR /&gt;&lt;BR /&gt;Is there a way to create a file geodatabase that includes all the layers, their visualization and attachments (if any)? I've tried to open the map in ArcGIS Pro and use the&amp;nbsp; "Extract Data" geoprocess tool. Sadly it didn't keep the original&amp;nbsp;visualization nor the attatchments, but it did keep all the layers saved into one file geodatabase.&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 16 May 2025 09:37:07 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615368#M64760</guid>
      <dc:creator>ErikAIversen</dc:creator>
      <dc:date>2025-05-16T09:37:07Z</dc:date>
    </item>
    <item>
      <title>Re: Creating a backup of map incl. feature layers, visualization and attachments</title>
      <link>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615369#M64761</link>
      <description>&lt;P&gt;Generally speaking, there isn't a way to store map properties, layer symbology, etc. in a geodatabase.&amp;nbsp; I have seem some custom approaches where these types of things are persisted in BLOB fields, or in large text fields with JSON content.&lt;/P&gt;&lt;P&gt;When I'm working on an AGOL project where I need to backup the data as well as maps, apps, etc., I'll usually do this:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;I use AGOL's built-in export process to create File GDB backups of the data.&amp;nbsp; FGDB is crucial (as opposed alternatives like shapefiles) because other data types involve the loss of some aspects of the data, such as null values or attachments.&lt;/LI&gt;&lt;LI&gt;I use a Python script that uses the ArcGIS API for Python (specifically the Item class) to connect to web maps, apps, etc. and downloads their definition as JSON files.&amp;nbsp; These JSON files capture map configuration like symbology and forms, element configuration and Data Expressions in dashboards, that kind of thing.&amp;nbsp; I push these JSON files into a Git repo, so I keep a complete history of these components.&lt;/LI&gt;&lt;/UL&gt;</description>
      <pubDate>Fri, 16 May 2025 09:49:36 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615369#M64761</guid>
      <dc:creator>MobiusSnake</dc:creator>
      <dc:date>2025-05-16T09:49:36Z</dc:date>
    </item>
    <item>
      <title>Re: Creating a backup of map incl. feature layers, visualization and attachments</title>
      <link>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615371#M64762</link>
      <description>&lt;P&gt;Thank you very much for the explanation. The built-in export process for AGOL, are you refering to this: &lt;A href="https://doc.arcgis.com/en/arcgis-online/analyze/extract-data-mv.htm" target="_blank"&gt;https://doc.arcgis.com/en/arcgis-online/analyze/extract-data-mv.htm&lt;/A&gt;&amp;nbsp;? Is there any way you would be willing to share the code you have used for the Python script for maps?&lt;/P&gt;</description>
      <pubDate>Fri, 16 May 2025 09:54:28 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615371#M64762</guid>
      <dc:creator>ErikAIversen</dc:creator>
      <dc:date>2025-05-16T09:54:28Z</dc:date>
    </item>
    <item>
      <title>Re: Creating a backup of map incl. feature layers, visualization and attachments</title>
      <link>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615381#M64763</link>
      <description>&lt;P&gt;I usually go with the Export Data button on the hosted feature layer's item page:&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MobiusSnake_0-1747391946497.png" style="width: 400px;"&gt;&lt;img src="https://community.esri.com/t5/image/serverpage/image-id/132396i0EDC7F4B27AB4BC4/image-size/medium?v=v2&amp;amp;px=400" role="button" title="MobiusSnake_0-1747391946497.png" alt="MobiusSnake_0-1747391946497.png" /&gt;&lt;/span&gt;&lt;/P&gt;</description>
      <pubDate>Fri, 16 May 2025 10:39:35 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615381#M64763</guid>
      <dc:creator>MobiusSnake</dc:creator>
      <dc:date>2025-05-16T10:39:35Z</dc:date>
    </item>
    <item>
      <title>Re: Creating a backup of map incl. feature layers, visualization and attachments</title>
      <link>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615389#M64764</link>
      <description>&lt;P&gt;Here are they two key functions I use for item exports and imports (this is typically when I've messed something up and need to roll back my changes).&amp;nbsp; This doesn't include connecting to ArcGIS Online to get an instance of the GIS class, that object gets passed into these functions along with the Item ID:&lt;/P&gt;&lt;LI-CODE lang="python"&gt;def download_data(gis: GIS, item_id: str, save_path: str):
    """
    Opens the specified item's data and saves it to the specified path.

    :param gis: The GIS connection.
    :param item_id: The Item ID to open.
    :param save_path: The location to save the item data.
    :return: None.
    """
    content_mgr = gis.content
    item = content_mgr.get(item_id)
    if item is None:
        raise Exception(f"download_data: Could not open item.")
    item_data = item.get_data()
    with open(save_path, "w") as output_file:
        json.dump(item_data, output_file)


def update_data(gis: GIS, item_id: str, file_path: str):
    """
    Updates the specified item with the data in the specified file.

    :param gis: The GIS connection.
    :param item_id: The Item ID to update.
    :param file_path: The file to update the item with.
    :return: None.
    """
    content_mgr = gis.content
    item = content_mgr.get(item_id)
    if item is None:
        raise Exception(f"update_data: Could not open item.")
    with open(file_path) as input_file:
        input_file_data = input_file.read()
    if not item.update(data=input_file_data):
        raise Exception(f"update_data: update() returned failure code.")&lt;/LI-CODE&gt;&lt;P&gt;Edit to add - there are a handful of settings that may not be captured with this approach, depending on the type of item you're downloading.&amp;nbsp; I haven't really tested it with Experience Builder but I have my suspicions it may not work so well; I typically use it with web maps and dashboards.&lt;/P&gt;</description>
      <pubDate>Fri, 16 May 2025 10:45:42 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615389#M64764</guid>
      <dc:creator>MobiusSnake</dc:creator>
      <dc:date>2025-05-16T10:45:42Z</dc:date>
    </item>
    <item>
      <title>Re: Creating a backup of map incl. feature layers, visualization and attachments</title>
      <link>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615462#M64767</link>
      <description>&lt;P&gt;Hi! I made two different scripts meant to be used as toolboxes in ArcGIS Pro inspired by your approach named "ExportBackup" and "RestoreMap":&lt;BR /&gt;&lt;BR /&gt;1. Find the map in AGOL you want to create a complete backup from and open it in ArcGIS Pro.&lt;BR /&gt;&lt;BR /&gt;2. Run this script which loops through every layer except basemaps, WMS etc. and saves them as individual .gdb (with attachments) and .lyrx (keeps symobology):&lt;BR /&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;import arcpy
import os
import csv
import re

# Get output folder from script tool parameter
output_folder = arcpy.GetParameterAsText(0)

# Prepare log
log_file_path = os.path.join(output_folder, "layer_export_log.csv")
log_rows = [["Original Layer Name", "Sanitized Name", "GDB Path", "Attachments Exported", "Symbology File"]]

# Helper to sanitize names
def sanitize_name(name):
    return re.sub(r'[^a-zA-Z0-9_]', '_', name)[:50]

# Get current ArcGIS Pro project and active map
project = arcpy.mp.ArcGISProject("CURRENT")
map_obj = project.activeMap

# Loop through all layers
for lyr in map_obj.listLayers():
    # Skip group layers, basemaps, or unsupported types
    if lyr.isGroupLayer or lyr.isBasemapLayer or not lyr.isFeatureLayer:
        try:
            arcpy.AddMessage(f"&lt;span class="lia-unicode-emoji" title=":next_track_button:"&gt;⏭&lt;/span&gt;️ Skipping: {lyr.name}")
        except:
            arcpy.AddMessage("&lt;span class="lia-unicode-emoji" title=":next_track_button:"&gt;⏭&lt;/span&gt;️ Skipping unsupported or service-based layer")
        continue

    # Try to access the layer name safely
    try:
        original_name = lyr.name
    except:
        original_name = "Unnamed_Layer"

    layer_name = sanitize_name(original_name)
    gdb_path = os.path.join(output_folder, f"{layer_name}.gdb")
    lyrx_path = os.path.join(output_folder, f"{layer_name}.lyrx")
    attachments_exported = "Included in GDB"

    arcpy.AddMessage(f"\n&lt;span class="lia-unicode-emoji" title=":counterclockwise_arrows_button:"&gt;🔄&lt;/span&gt; Exporting: {original_name} → {layer_name}")

    # Create File GDB
    if not arcpy.Exists(gdb_path):
        arcpy.management.CreateFileGDB(output_folder, f"{layer_name}.gdb")

    out_feature = os.path.join(gdb_path, layer_name)

    try:
        # Export feature class
        arcpy.conversion.FeatureClassToFeatureClass(
            in_features=lyr,
            out_path=gdb_path,
            out_name=layer_name
        )
        arcpy.AddMessage("&lt;span class="lia-unicode-emoji" title=":paperclip:"&gt;📎&lt;/span&gt; Attachments preserved within File Geodatabase.")

        # Temporarily add exported data to map
        temp_layer = map_obj.addDataFromPath(out_feature)

        # Copy symbology from original layer
        try:
            temp_layer.symbology = lyr.symbology
            arcpy.AddMessage(":artist_palette:&lt;/img&gt; Symbology copied from original layer.")
        except Exception as e:
            arcpy.AddWarning(f":warning:&lt;/img&gt; Could not copy symbology: {str(e)}")

        # Save styled layer to .lyrx
        temp_layer.saveACopy(lyrx_path)
        arcpy.AddMessage(f":floppy_disk:&lt;/img&gt; Symbology saved to: {lyrx_path}")

        # Clean up
        map_obj.removeLayer(temp_layer)

    except Exception as e:
        arcpy.AddWarning(f"&lt;span class="lia-unicode-emoji" title=":cross_mark:"&gt;❌&lt;/span&gt; Failed to export {original_name}: {str(e)}")
        continue

    # Log export result
    log_rows.append([original_name, layer_name, gdb_path, attachments_exported, lyrx_path])

# Write CSV log
with open(log_file_path, mode="w", newline='', encoding="utf-8") as log_file:
    writer = csv.writer(log_file)
    writer.writerows(log_rows)

arcpy.AddMessage(f"\n&lt;span class="lia-unicode-emoji" title=":memo:"&gt;📝&lt;/span&gt; Log file saved to: {log_file_path}")
arcpy.AddMessage("&lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Done! All eligible layers exported.")&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;3. Run this script to restore the map just like it was:&lt;/P&gt;&lt;LI-CODE lang="python"&gt;import arcpy
import os

# Folder containing .gdb and matching .lyrx files
input_folder = arcpy.GetParameterAsText(0)
project = arcpy.mp.ArcGISProject("CURRENT")
map_obj = project.activeMap

arcpy.AddMessage(f":open_file_folder:&lt;/img&gt; Restoring from: {input_folder}")

for item in os.listdir(input_folder):
    if item.lower().endswith(".gdb"):
        layer_name = os.path.splitext(item)[0]
        gdb_path = os.path.join(input_folder, item)
        lyrx_path = os.path.join(input_folder, f"{layer_name}.lyrx")

        arcpy.env.workspace = gdb_path
        feature_classes = arcpy.ListFeatureClasses()
        if not feature_classes:
            arcpy.AddWarning(f":warning:&lt;/img&gt; No feature classes in {gdb_path}.")
            continue

        fc_path = os.path.join(gdb_path, feature_classes[0])
        arcpy.AddMessage(f"&lt;span class="lia-unicode-emoji" title=":heavy_plus_sign:"&gt;➕&lt;/span&gt; Adding: {layer_name}")

        try:
            new_layer = map_obj.addDataFromPath(fc_path)

            if os.path.exists(lyrx_path):
                try:
                    sym_layer_file = arcpy.mp.LayerFile(lyrx_path)
                    sym_layer = sym_layer_file.listLayers()[0]
                    new_layer.symbology = sym_layer.symbology
                    arcpy.AddMessage(f":artist_palette:&lt;/img&gt; Symbology copied from: {lyrx_path}")
                except Exception as e:
                    arcpy.AddWarning(f":warning:&lt;/img&gt; Failed to copy symbology: {str(e)}")
            else:
                arcpy.AddWarning(f":artist_palette:&lt;/img&gt; No .lyrx found for: {layer_name}")
        except Exception as e:
            arcpy.AddWarning(f"&lt;span class="lia-unicode-emoji" title=":cross_mark:"&gt;❌&lt;/span&gt; Failed to load {layer_name}: {str(e)}")

arcpy.AddMessage("&lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Done restoring layers.")&lt;/LI-CODE&gt;&lt;P&gt;&lt;BR /&gt;Both toolboxes has to be set up with a mandatory output folder for the "ExportBackup" and input folder for "RestoreMap". Works like a charm!&lt;/P&gt;</description>
      <pubDate>Fri, 16 May 2025 14:36:22 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-online-questions/creating-a-backup-of-map-incl-feature-layers/m-p/1615462#M64767</guid>
      <dc:creator>ErikAIversen</dc:creator>
      <dc:date>2025-05-16T14:36:22Z</dc:date>
    </item>
  </channel>
</rss>

