From aef50a4409156bb6a3335f9ed8bf26dee4fe3399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Sat, 24 Feb 2024 15:25:18 +0100 Subject: [PATCH 01/35] add audit feature --- .../backup/Intune/backup_AppProtection.py | 14 +- src/IntuneCD/backup/Intune/backup_apns.py | 15 +- .../backup/Intune/backup_appConfiguration.py | 16 +- .../Intune/backup_appleEnrollmentProfile.py | 16 +- .../backup/Intune/backup_applications.py | 14 +- .../backup/Intune/backup_assignmentFilters.py | 16 +- .../backup/Intune/backup_compliance.py | 14 +- .../backup/Intune/backup_compliancePartner.py | 14 +- .../Intune/backup_configurationPolicies.py | 14 +- .../backup_customAttributeShellScript.py | 14 +- .../backup/Intune/backup_deviceCategories.py | 16 +- .../Intune/backup_deviceManagementSettings.py | 17 +- .../Intune/backup_enrollmentConfigurations.py | 14 +- .../Intune/backup_groupPolicyConfiguration.py | 14 +- .../backup/Intune/backup_managedGPlay.py | 15 +- .../backup/Intune/backup_managementIntents.py | 16 +- .../backup/Intune/backup_managementPartner.py | 14 +- .../Intune/backup_notificationTemplate.py | 14 +- .../backup/Intune/backup_powershellScripts.py | 16 +- .../Intune/backup_proactiveRemediation.py | 16 +- src/IntuneCD/backup/Intune/backup_profiles.py | 40 ++++- .../Intune/backup_remoteAssistancePartner.py | 14 +- src/IntuneCD/backup/Intune/backup_roles.py | 14 +- .../backup/Intune/backup_scopeTags.py | 14 +- .../backup/Intune/backup_shellScripts.py | 14 +- .../backup/Intune/backup_vppTokens.py | 14 +- .../Intune/backup_windowsDriverUpdates.py | 14 +- .../Intune/backup_windowsEnrollmentProfile.py | 14 +- .../Intune/backup_windowsFeatureUpdates.py | 14 +- .../Intune/backup_windowsQualityUpdates.py | 14 +- src/IntuneCD/backup_intune.py | 97 +++++++---- src/IntuneCD/intunecdlib/graph_request.py | 42 +++++ .../intunecdlib/process_audit_data.py | 150 ++++++++++++++++++ src/IntuneCD/run_backup.py | 5 + tests/Backup/Intune/test_backup_apns.py | 6 +- .../Intune/test_backup_appConfiguration.py | 27 +++- .../Intune/test_backup_appProtection.py | 43 ++++- .../test_backup_appleEnrollmentProfile.py | 12 +- .../Backup/Intune/test_backup_applications.py | 26 +-- .../Intune/test_backup_assignmentFilter.py | 12 +- tests/Backup/Intune/test_backup_compliance.py | 27 +++- .../Intune/test_backup_compliancePartner.py | 10 +- .../test_backup_configurationPolicies.py | 27 +++- .../test_backup_customAttributeShellScript.py | 35 +++- .../Intune/test_backup_deviceCategories.py | 12 +- .../test_backup_deviceManagementSettings.py | 4 +- .../test_backup_enrollmentConfigurations.py | 35 +++- .../test_backup_groupPolicyConfiguration.py | 27 +++- .../Backup/Intune/test_backup_managedGPlay.py | 10 +- .../Intune/test_backup_managementIntents.py | 27 +++- .../Intune/test_backup_managementPartner.py | 14 +- .../test_backup_notificationTemplate.py | 12 +- .../Intune/test_backup_powershellScripts.py | 35 +++- .../test_backup_proactiveRemediation.py | 37 ++++- tests/Backup/Intune/test_backup_profiles.py | 15 +- .../test_backup_remoteAssistancePartner.py | 18 ++- tests/Backup/Intune/test_backup_roles.py | 10 +- tests/Backup/Intune/test_backup_scopeTags.py | 8 +- .../Backup/Intune/test_backup_shellScripts.py | 35 +++- tests/Backup/Intune/test_backup_vppTokens.py | 14 +- .../test_backup_windowsDriverUpdates.py | 27 +++- .../test_backup_windowsEnrollmentProfile.py | 27 +++- .../test_backup_windowsFeatureUpdates.py | 27 +++- .../test_backup_windowsQualityUpdates.py | 27 +++- 64 files changed, 1178 insertions(+), 227 deletions(-) create mode 100644 src/IntuneCD/intunecdlib/process_audit_data.py diff --git a/src/IntuneCD/backup/Intune/backup_AppProtection.py b/src/IntuneCD/backup/Intune/backup_AppProtection.py index 102428f0..36bdd4e0 100644 --- a/src/IntuneCD/backup/Intune/backup_AppProtection.py +++ b/src/IntuneCD/backup/Intune/backup_AppProtection.py @@ -8,7 +8,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -17,7 +18,7 @@ # Get all App Protection policies and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all App Protection policies in Intune to a JSON or YAML file. @@ -76,4 +77,13 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_apns.py b/src/IntuneCD/backup/Intune/backup_apns.py index 0a8703b9..11003639 100644 --- a/src/IntuneCD/backup/Intune/backup_apns.py +++ b/src/IntuneCD/backup/Intune/backup_apns.py @@ -6,7 +6,8 @@ """ from ...intunecdlib.clean_filename import clean_filename -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -17,7 +18,7 @@ # Get APNs information and save in specified path -def savebackup(path, output, token): +def savebackup(path, output, audit, token): """ Save Apple Push Notification setting to a JSON or YAML file. @@ -43,4 +44,14 @@ def savebackup(path, output, token): results["outputs"].append(fname) + if audit: + graph_filter = "resources/any(s:s/auditResourceType eq 'Microsoft.Management.Services.Api.ApplePushNotificationCertificate')" + audit_data = makeAuditRequest( + "", + graph_filter, + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_appConfiguration.py b/src/IntuneCD/backup/Intune/backup_appConfiguration.py index 8174c916..d4ebda50 100644 --- a/src/IntuneCD/backup/Intune/backup_appConfiguration.py +++ b/src/IntuneCD/backup/Intune/backup_appConfiguration.py @@ -11,7 +11,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -23,7 +24,7 @@ # Get all App Configuration policies and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all App Configuration policies in Intune to a JSON or YAML file. @@ -90,4 +91,15 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data( + audit_data, path, f"{configpath}{fname}.{output}" + ) + return results diff --git a/src/IntuneCD/backup/Intune/backup_appleEnrollmentProfile.py b/src/IntuneCD/backup/Intune/backup_appleEnrollmentProfile.py index 8303d228..53e74be6 100644 --- a/src/IntuneCD/backup/Intune/backup_appleEnrollmentProfile.py +++ b/src/IntuneCD/backup/Intune/backup_appleEnrollmentProfile.py @@ -8,7 +8,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_request -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -17,7 +18,7 @@ # Get all Apple Enrollment Profiles and save them in specified path -def savebackup(path, output, token, prefix, append_id): +def savebackup(path, output, token, prefix, append_id, audit): """ Saves all Apple Enrollment Profiles in Intune to a JSON or YAML file. @@ -63,4 +64,15 @@ def savebackup(path, output, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data( + audit_data, path, f"{configpath}{fname}.{output}" + ) + return results diff --git a/src/IntuneCD/backup/Intune/backup_applications.py b/src/IntuneCD/backup/Intune/backup_applications.py index 07a9cc1b..42a50b20 100644 --- a/src/IntuneCD/backup/Intune/backup_applications.py +++ b/src/IntuneCD/backup/Intune/backup_applications.py @@ -9,7 +9,8 @@ from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -37,7 +38,7 @@ def match(platform, odata_input) -> bool: # Get all applications and save them in specified path -def savebackup(path, output, exclude, token, append_id): +def savebackup(path, output, exclude, token, append_id, audit): """ Saves all applications in Intune to a JSON or YAML file. @@ -137,4 +138,13 @@ def savebackup(path, output, exclude, token, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_assignmentFilters.py b/src/IntuneCD/backup/Intune/backup_assignmentFilters.py index 5540977a..edee0b9c 100644 --- a/src/IntuneCD/backup/Intune/backup_assignmentFilters.py +++ b/src/IntuneCD/backup/Intune/backup_assignmentFilters.py @@ -7,7 +7,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -16,7 +17,7 @@ # Get all Filters and save them in specified path -def savebackup(path, output, token, prefix, append_id): +def savebackup(path, output, token, prefix, append_id, audit): """ Saves all Filter in Intune to a JSON or YAML file. @@ -49,4 +50,15 @@ def savebackup(path, output, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data( + audit_data, path, f"{configpath}{fname}.{output}" + ) + return results diff --git a/src/IntuneCD/backup/Intune/backup_compliance.py b/src/IntuneCD/backup/Intune/backup_compliance.py index 70099ab2..c81ed93f 100644 --- a/src/IntuneCD/backup/Intune/backup_compliance.py +++ b/src/IntuneCD/backup/Intune/backup_compliance.py @@ -8,7 +8,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -17,7 +18,7 @@ # Get all Compliance policies and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Compliance policies in Intune to a JSON or YAML file. @@ -77,4 +78,13 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_compliancePartner.py b/src/IntuneCD/backup/Intune/backup_compliancePartner.py index 23412f7f..dd50ade0 100644 --- a/src/IntuneCD/backup/Intune/backup_compliancePartner.py +++ b/src/IntuneCD/backup/Intune/backup_compliancePartner.py @@ -6,7 +6,8 @@ """ from ...intunecdlib.clean_filename import clean_filename -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -17,7 +18,7 @@ # Get all Compliance Partners and save them in specified path -def savebackup(path, output, exclude, token, append_id): +def savebackup(path, output, exclude, token, append_id, audit): """ Saves all Compliance Partners in Intune to a JSON or YAML file. @@ -56,4 +57,13 @@ def savebackup(path, output, exclude, token, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_configurationPolicies.py b/src/IntuneCD/backup/Intune/backup_configurationPolicies.py index 36ce6f2d..1bf570e8 100644 --- a/src/IntuneCD/backup/Intune/backup_configurationPolicies.py +++ b/src/IntuneCD/backup/Intune/backup_configurationPolicies.py @@ -13,7 +13,8 @@ get_object_assignment, get_object_details, ) -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -22,7 +23,7 @@ # Get all Configuration Policies and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Configuration Policies in Intune to a JSON or YAML file. @@ -83,4 +84,13 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_customAttributeShellScript.py b/src/IntuneCD/backup/Intune/backup_customAttributeShellScript.py index 5905442d..f4c17b4f 100644 --- a/src/IntuneCD/backup/Intune/backup_customAttributeShellScript.py +++ b/src/IntuneCD/backup/Intune/backup_customAttributeShellScript.py @@ -15,7 +15,8 @@ batch_request, get_object_assignment, ) -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -27,7 +28,7 @@ # Get all Custom Attribute Shell scripts and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Custom Attribute Shell scripts in Intune to a JSON or YAML file and script files. @@ -89,4 +90,13 @@ def savebackup(path, output, exclude, token, prefix, append_id): f = open(configpath + "Script Data/" + script_file_name, "w", encoding="utf-8") f.write(decoded) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_deviceCategories.py b/src/IntuneCD/backup/Intune/backup_deviceCategories.py index da40d0f6..a56c2454 100644 --- a/src/IntuneCD/backup/Intune/backup_deviceCategories.py +++ b/src/IntuneCD/backup/Intune/backup_deviceCategories.py @@ -7,7 +7,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -16,7 +17,7 @@ # Get Device Categories information and save in specified path -def savebackup(path, output, token, prefix, append_id): +def savebackup(path, output, token, prefix, append_id, audit): """ Save Device Categories to a JSON or YAML file. @@ -49,4 +50,15 @@ def savebackup(path, output, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data( + audit_data, path, f"{configpath}{fname}.{output}" + ) + return results diff --git a/src/IntuneCD/backup/Intune/backup_deviceManagementSettings.py b/src/IntuneCD/backup/Intune/backup_deviceManagementSettings.py index fe7d948d..70db0bb7 100644 --- a/src/IntuneCD/backup/Intune/backup_deviceManagementSettings.py +++ b/src/IntuneCD/backup/Intune/backup_deviceManagementSettings.py @@ -6,7 +6,8 @@ """ from ...intunecdlib.clean_filename import clean_filename -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -15,7 +16,7 @@ # Get settings and save in specified path -def savebackup(path, output, token): +def savebackup(path, output, audit, token): """ Save Device Management Setting to a JSON or YAML file. @@ -41,4 +42,16 @@ def savebackup(path, output, token): results["outputs"].append(fname) + if audit: + graph_filter = ( + "resources/any(s:s/auditResourceType eq 'DeviceManagementSettings')" + ) + audit_data = makeAuditRequest( + "", + graph_filter, + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_enrollmentConfigurations.py b/src/IntuneCD/backup/Intune/backup_enrollmentConfigurations.py index 30aa462d..d385e9ff 100644 --- a/src/IntuneCD/backup/Intune/backup_enrollmentConfigurations.py +++ b/src/IntuneCD/backup/Intune/backup_enrollmentConfigurations.py @@ -10,7 +10,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -21,7 +22,7 @@ # Get all Enrollment Configurations and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Enrollment Configurations in Intune to a JSON or YAML file. @@ -77,4 +78,13 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_groupPolicyConfiguration.py b/src/IntuneCD/backup/Intune/backup_groupPolicyConfiguration.py index f4aecd8f..f2742393 100644 --- a/src/IntuneCD/backup/Intune/backup_groupPolicyConfiguration.py +++ b/src/IntuneCD/backup/Intune/backup_groupPolicyConfiguration.py @@ -8,7 +8,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -17,7 +18,7 @@ # Get all Group Policy Configurations and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Group Policy Configurations in Intune to a JSON or YAML file. @@ -76,4 +77,13 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_managedGPlay.py b/src/IntuneCD/backup/Intune/backup_managedGPlay.py index 37e07f5e..4c27b34c 100644 --- a/src/IntuneCD/backup/Intune/backup_managedGPlay.py +++ b/src/IntuneCD/backup/Intune/backup_managedGPlay.py @@ -6,7 +6,8 @@ """ from ...intunecdlib.clean_filename import clean_filename -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -15,7 +16,7 @@ # Get Managed Google Play information and save in specified path -def savebackup(path, output, exclude, token, append_id): +def savebackup(path, output, exclude, token, append_id, audit): """ Saves Managed Google Play information in Intune to a JSON or YAML file. @@ -47,4 +48,14 @@ def savebackup(path, output, exclude, token, append_id): results["outputs"].append(fname) + if audit: + graph_filter = "resources/any(s:s/auditResourceType eq 'Microsoft.Management.Services.Api.AndroidManagedStoreAccountEnterpriseSettings')" + audit_data = makeAuditRequest( + "", + graph_filter, + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_managementIntents.py b/src/IntuneCD/backup/Intune/backup_managementIntents.py index 97636202..81b3fa17 100644 --- a/src/IntuneCD/backup/Intune/backup_managementIntents.py +++ b/src/IntuneCD/backup/Intune/backup_managementIntents.py @@ -12,7 +12,8 @@ batch_intents, get_object_assignment, ) -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.save_output import save_output # Set MS Graph base endpoint @@ -21,7 +22,7 @@ # Get all Intents and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Intents in Intune to a JSON or YAML file. @@ -76,4 +77,15 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data( + audit_data, path, f"{configpath}{fname}.{output}" + ) + return results diff --git a/src/IntuneCD/backup/Intune/backup_managementPartner.py b/src/IntuneCD/backup/Intune/backup_managementPartner.py index b9ef13e5..dc4a2915 100644 --- a/src/IntuneCD/backup/Intune/backup_managementPartner.py +++ b/src/IntuneCD/backup/Intune/backup_managementPartner.py @@ -6,7 +6,8 @@ """ from ...intunecdlib.clean_filename import clean_filename -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -15,7 +16,7 @@ # Get all Management Partners and save them in specified path -def savebackup(path, output, token, append_id): +def savebackup(path, output, token, append_id, audit): """ Saves Management Partner information in Intune to a JSON or YAML file. @@ -48,4 +49,13 @@ def savebackup(path, output, token, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_notificationTemplate.py b/src/IntuneCD/backup/Intune/backup_notificationTemplate.py index 46ebd02b..9cb81f2f 100644 --- a/src/IntuneCD/backup/Intune/backup_notificationTemplate.py +++ b/src/IntuneCD/backup/Intune/backup_notificationTemplate.py @@ -7,7 +7,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -18,7 +19,7 @@ # Get all Notification Templates and save them in specified path -def savebackup(path, output, token, prefix, append_id): +def savebackup(path, output, token, prefix, append_id, audit): """ Saves all Notification Templates in Intune to a JSON or YAML file. @@ -60,4 +61,13 @@ def savebackup(path, output, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_powershellScripts.py b/src/IntuneCD/backup/Intune/backup_powershellScripts.py index 57e9804a..37ad5f5d 100644 --- a/src/IntuneCD/backup/Intune/backup_powershellScripts.py +++ b/src/IntuneCD/backup/Intune/backup_powershellScripts.py @@ -15,7 +15,8 @@ batch_request, get_object_assignment, ) -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -24,7 +25,7 @@ # Get all Powershell scripts and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Powershell scripts in Intune to a JSON or YAML file and script files. @@ -79,6 +80,17 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data( + audit_data, path, f"{configpath}{fname}.{output}" + ) + # Save Powershell script data to the script data folder if script_data.get("scriptContent"): if not os.path.exists(configpath + "Script Data/"): diff --git a/src/IntuneCD/backup/Intune/backup_proactiveRemediation.py b/src/IntuneCD/backup/Intune/backup_proactiveRemediation.py index 20915bb2..2c0c0ff6 100644 --- a/src/IntuneCD/backup/Intune/backup_proactiveRemediation.py +++ b/src/IntuneCD/backup/Intune/backup_proactiveRemediation.py @@ -15,7 +15,8 @@ batch_request, get_object_assignment, ) -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -24,7 +25,7 @@ # Get all Proactive Remediation and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Proactive Remediation in Intune to a JSON or YAML file and script files. @@ -78,6 +79,17 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data( + audit_data, path, f"{configpath}{fname}.{output}" + ) + if not os.path.exists(f"{configpath}/Script Data"): os.makedirs(f"{configpath}/Script Data") diff --git a/src/IntuneCD/backup/Intune/backup_profiles.py b/src/IntuneCD/backup/Intune/backup_profiles.py index 83033094..ce0c2469 100644 --- a/src/IntuneCD/backup/Intune/backup_profiles.py +++ b/src/IntuneCD/backup/Intune/backup_profiles.py @@ -11,7 +11,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -20,7 +21,9 @@ # Get all Device Configurations and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, ignore_omasettings): +def savebackup( + path, output, exclude, token, prefix, append_id, ignore_omasettings, audit +): """ Saves all Device Configurations in Intune to a JSON or YAML file and custom macOS/iOS to .mobileconfig. @@ -83,6 +86,17 @@ def savebackup(path, output, exclude, token, prefix, append_id, ignore_omasettin results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data( + audit_data, path, f"{configpath}{fname}.{output}" + ) + # If Device Configuration is custom Win10 and the OMA settings are # encrypted, get them in plain text elif profile[ @@ -126,6 +140,17 @@ def savebackup(path, output, exclude, token, prefix, append_id, ignore_omasettin results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data( + audit_data, path, f"{configpath}{fname}.{output}" + ) + # If Device Configuration are not custom, save it as JSON or YAML # depending on configured value in "-o" else: @@ -133,4 +158,15 @@ def savebackup(path, output, exclude, token, prefix, append_id, ignore_omasettin results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data( + audit_data, path, f"{configpath}{fname}.{output}" + ) + return results diff --git a/src/IntuneCD/backup/Intune/backup_remoteAssistancePartner.py b/src/IntuneCD/backup/Intune/backup_remoteAssistancePartner.py index 6208183f..1e8b3d4d 100644 --- a/src/IntuneCD/backup/Intune/backup_remoteAssistancePartner.py +++ b/src/IntuneCD/backup/Intune/backup_remoteAssistancePartner.py @@ -6,7 +6,8 @@ """ from ...intunecdlib.clean_filename import clean_filename -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -15,7 +16,7 @@ # Get all Remote Assistance Partners and save them in specified path -def savebackup(path, output, token, append_id): +def savebackup(path, output, token, append_id, audit): """ Saves all Remote Assistance Partners in Intune to a JSON or YAML file. @@ -48,4 +49,13 @@ def savebackup(path, output, token, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_roles.py b/src/IntuneCD/backup/Intune/backup_roles.py index bf6ba572..ad8afc87 100644 --- a/src/IntuneCD/backup/Intune/backup_roles.py +++ b/src/IntuneCD/backup/Intune/backup_roles.py @@ -6,7 +6,8 @@ """ from ...intunecdlib.clean_filename import clean_filename -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -15,7 +16,7 @@ # Get all Roles and save them in specified path -def savebackup(path, output, exclude, token, append_id): +def savebackup(path, output, exclude, token, append_id, audit): """ Saves all Roles in Intune to a JSON or YAML file. @@ -106,4 +107,13 @@ def _get_group_names(obj): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_scopeTags.py b/src/IntuneCD/backup/Intune/backup_scopeTags.py index 67c1a98c..28358ba1 100644 --- a/src/IntuneCD/backup/Intune/backup_scopeTags.py +++ b/src/IntuneCD/backup/Intune/backup_scopeTags.py @@ -7,7 +7,8 @@ from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -16,7 +17,7 @@ # Get Scope Tags and save in specified path -def savebackup(path, output, exclude, token, append_id): +def savebackup(path, output, exclude, token, append_id, audit): """ Save Scope Tags to a JSON or YAML file. @@ -56,4 +57,13 @@ def savebackup(path, output, exclude, token, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + tag_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_shellScripts.py b/src/IntuneCD/backup/Intune/backup_shellScripts.py index 5472e85b..52bd6d15 100644 --- a/src/IntuneCD/backup/Intune/backup_shellScripts.py +++ b/src/IntuneCD/backup/Intune/backup_shellScripts.py @@ -15,7 +15,8 @@ batch_request, get_object_assignment, ) -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -27,7 +28,7 @@ # Get all Shell scripts and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Shell scripts in Intune to a JSON or YAML file and script files. @@ -79,6 +80,15 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + # Save Shell script data to the script data folder if not os.path.exists(configpath + "Script Data/"): os.makedirs(configpath + "Script Data/") diff --git a/src/IntuneCD/backup/Intune/backup_vppTokens.py b/src/IntuneCD/backup/Intune/backup_vppTokens.py index 378d478a..93ac662e 100644 --- a/src/IntuneCD/backup/Intune/backup_vppTokens.py +++ b/src/IntuneCD/backup/Intune/backup_vppTokens.py @@ -6,7 +6,8 @@ """ from ...intunecdlib.clean_filename import clean_filename -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -15,7 +16,7 @@ # Get all VPP tokens and save them in specified path -def savebackup(path, output, token, append_id): +def savebackup(path, output, token, append_id, audit): """ Save all VPP tokens in Intune to a JSON or YAML file. @@ -46,4 +47,13 @@ def savebackup(path, output, token, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_windowsDriverUpdates.py b/src/IntuneCD/backup/Intune/backup_windowsDriverUpdates.py index 4b7fa714..d8639d6d 100644 --- a/src/IntuneCD/backup/Intune/backup_windowsDriverUpdates.py +++ b/src/IntuneCD/backup/Intune/backup_windowsDriverUpdates.py @@ -8,7 +8,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -19,7 +20,7 @@ # Get all Windows Driver Profiles and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Windows Driver Update Profiles in Intune to a JSON or YAML file. @@ -65,4 +66,13 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_windowsEnrollmentProfile.py b/src/IntuneCD/backup/Intune/backup_windowsEnrollmentProfile.py index 0a4272e9..d989ce55 100644 --- a/src/IntuneCD/backup/Intune/backup_windowsEnrollmentProfile.py +++ b/src/IntuneCD/backup/Intune/backup_windowsEnrollmentProfile.py @@ -8,7 +8,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -17,7 +18,7 @@ # Get all Windows Enrollment Profiles and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Windows Enrollment Profiles in Intune to a JSON or YAML file. @@ -63,4 +64,13 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_windowsFeatureUpdates.py b/src/IntuneCD/backup/Intune/backup_windowsFeatureUpdates.py index 88f3ed20..3be37095 100644 --- a/src/IntuneCD/backup/Intune/backup_windowsFeatureUpdates.py +++ b/src/IntuneCD/backup/Intune/backup_windowsFeatureUpdates.py @@ -8,7 +8,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -19,7 +20,7 @@ # Get all Windows Feature Profiles and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Windows Feature Update Profiles in Intune to a JSON or YAML file. @@ -65,4 +66,13 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup/Intune/backup_windowsQualityUpdates.py b/src/IntuneCD/backup/Intune/backup_windowsQualityUpdates.py index b2f893dd..15eebb66 100644 --- a/src/IntuneCD/backup/Intune/backup_windowsQualityUpdates.py +++ b/src/IntuneCD/backup/Intune/backup_windowsQualityUpdates.py @@ -8,7 +8,8 @@ from ...intunecdlib.check_prefix import check_prefix_match from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment -from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -19,7 +20,7 @@ # Get all Windows Quality Profiles and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, audit): """ Saves all Windows Quality Update Profiles in Intune to a JSON or YAML file. @@ -65,4 +66,13 @@ def savebackup(path, output, exclude, token, prefix, append_id): results["outputs"].append(fname) + if audit: + audit_data = makeAuditRequest( + graph_id, + "", + token, + ) + if audit_data: + process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") + return results diff --git a/src/IntuneCD/backup_intune.py b/src/IntuneCD/backup_intune.py index 1bbc6c79..415cbe62 100644 --- a/src/IntuneCD/backup_intune.py +++ b/src/IntuneCD/backup_intune.py @@ -12,71 +12,88 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args if "AppConfigurations" not in exclude: from .backup.Intune.backup_appConfiguration import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "AppProtection" not in exclude: from .backup.Intune.backup_AppProtection import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "APNs" not in exclude: from .backup.Intune.backup_apns import savebackup - results.append(savebackup(path, output, token)) + results.append(savebackup(path, output, args.audit, token)) if "VPP" not in exclude: from .backup.Intune.backup_vppTokens import savebackup - results.append(savebackup(path, output, token, append_id)) + results.append(savebackup(path, output, token, append_id, args.audit)) if "Applications" not in exclude: from .backup.Intune.backup_applications import savebackup - results.append(savebackup(path, output, exclude, token, append_id)) + results.append(savebackup(path, output, exclude, token, append_id, args.audit)) if "Compliance" not in exclude: from .backup.Intune.backup_compliance import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "DeviceManagementSettings" not in exclude: from .backup.Intune.backup_deviceManagementSettings import savebackup - results.append(savebackup(path, output, token)) + results.append(savebackup(path, output, args.audit, token)) if "DeviceCategories" not in exclude: from .backup.Intune.backup_deviceCategories import savebackup - results.append(savebackup(path, output, token, prefix, append_id)) + results.append(savebackup(path, output, token, prefix, append_id, args.audit)) if "NotificationTemplate" not in exclude: from .backup.Intune.backup_notificationTemplate import savebackup - results.append(savebackup(path, output, token, prefix, append_id)) + results.append(savebackup(path, output, token, prefix, append_id, args.audit)) if "Profiles" not in exclude: from .backup.Intune.backup_profiles import savebackup results.append( savebackup( - path, output, exclude, token, prefix, append_id, args.ignore_omasettings + path, + output, + exclude, + token, + prefix, + append_id, + args.ignore_omasettings, + args.audit, ) ) if "GPOConfigurations" not in exclude: from .backup.Intune.backup_groupPolicyConfiguration import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "AppleEnrollmentProfile" not in exclude: from .backup.Intune.backup_appleEnrollmentProfile import savebackup - results.append(savebackup(path, output, token, prefix, append_id)) + results.append(savebackup(path, output, token, prefix, append_id, args.audit)) if "WindowsEnrollmentProfile" not in exclude: from .backup.Intune.backup_windowsEnrollmentProfile import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "EnrollmentStatusPage" not in exclude: from .backup.Intune.backup_enrollmentStatusPage import savebackup @@ -86,7 +103,9 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args if "EnrollmentConfigurations" not in exclude: from .backup.Intune.backup_enrollmentConfigurations import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if args.autopilot == "True": from .backup.Intune.backup_autopilotDevices import savebackup @@ -96,57 +115,69 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args if "Filters" not in exclude: from .backup.Intune.backup_assignmentFilters import savebackup - results.append(savebackup(path, output, token, prefix, append_id)) + results.append(savebackup(path, output, token, prefix, append_id, args.audit)) if "ManagedGooglePlay" not in exclude: from .backup.Intune.backup_managedGPlay import savebackup - results.append(savebackup(path, output, exclude, token, append_id)) + results.append(savebackup(path, output, exclude, token, append_id, args.audit)) if "Intents" not in exclude: from .backup.Intune.backup_managementIntents import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "CompliancePartner" not in exclude: from .backup.Intune.backup_compliancePartner import savebackup - results.append(savebackup(path, output, exclude, token, append_id)) + results.append(savebackup(path, output, exclude, token, append_id, args.audit)) if "ManagementPartner" not in exclude: from .backup.Intune.backup_managementPartner import savebackup - results.append(savebackup(path, output, token, append_id)) + results.append(savebackup(path, output, token, append_id, args.audit)) if "RemoteAssistancePartner" not in exclude: from .backup.Intune.backup_remoteAssistancePartner import savebackup - results.append(savebackup(path, output, token, append_id)) + results.append(savebackup(path, output, token, append_id, args.audit)) if "ProactiveRemediation" not in exclude: from .backup.Intune.backup_proactiveRemediation import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "PowershellScripts" not in exclude: from .backup.Intune.backup_powershellScripts import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "ShellScripts" not in exclude: from .backup.Intune.backup_shellScripts import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "CustomAttributes" not in exclude: from .backup.Intune.backup_customAttributeShellScript import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "ConfigurationPolicies" not in exclude: from .backup.Intune.backup_configurationPolicies import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "ConditionalAccess" not in exclude: from .backup.Intune.backup_conditionalAccess import savebackup @@ -156,24 +187,30 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args if "WindowsDriverUpdates" not in exclude: from .backup.Intune.backup_windowsDriverUpdates import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "WindowsFeatureUpdates" not in exclude: from .backup.Intune.backup_windowsFeatureUpdates import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "WindowsQualityUpdates" not in exclude: from .backup.Intune.backup_windowsQualityUpdates import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, args.audit) + ) if "Roles" not in exclude: from .backup.Intune.backup_roles import savebackup - results.append(savebackup(path, output, exclude, token, append_id)) + results.append(savebackup(path, output, exclude, token, append_id, args.audit)) if "ScopeTags" not in exclude: from .backup.Intune.backup_scopeTags import savebackup - results.append(savebackup(path, output, exclude, token, append_id)) + results.append(savebackup(path, output, exclude, token, append_id, args.audit)) diff --git a/src/IntuneCD/intunecdlib/graph_request.py b/src/IntuneCD/intunecdlib/graph_request.py index 176c8abe..30c16306 100644 --- a/src/IntuneCD/intunecdlib/graph_request.py +++ b/src/IntuneCD/intunecdlib/graph_request.py @@ -5,6 +5,7 @@ This module contains the functions to make API requests to the Microsoft Graph API. """ +import datetime import json import time @@ -235,3 +236,44 @@ def makeapirequestPut(patchEndpoint, token, q_param=None, jdata=None, status_cod raise requests.exceptions.HTTPError( "Request failed with {} - {}".format(response.status_code, response.text) ) + + +def makeAuditRequest(pid, graph_filter, token): + """ + This function makes a GET request to the Microsoft Graph API to get the audit logs for a specific object. + + :param pid: The ID of the object to get the audit logs for. + :param graph_filter: The filter to use for the request. + :param token: The token to use for authenticating the request. + """ + + # Get the current date and time and set time to 00:00:00 + start_date = datetime.datetime.now().strftime("%Y-%m-%dT00:00:00.000Z") + # Get the current date and time + end_date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ") + # Create query to get audit logs for the object + if not graph_filter: + graph_filter = f"resources/any(s:s/resourceId eq '{pid}')" + q_param = { + "$filter": f"{graph_filter} and activityDateTime gt {start_date} and activityDateTime le {end_date} and activityOperationType ne 'Get'", + "$select": "actor,activityDateTime,activityOperationType,activityResult", + "$orderby": "activityDateTime desc", + } + + # Make the request to the Microsoft Graph API + endpoint = "https://graph.microsoft.com/v1.0/deviceManagement/auditEvents" + data = makeapirequest(endpoint, token, q_param) + + # If there are audit logs, return the latest one + if data["value"]: + # is the actor an app or a user? + if data["value"][0]["actor"]["auditActorType"] == "ItPro": + actor = data["value"][0]["actor"].get("userPrincipalName") + else: + actor = data["value"][0]["actor"].get("applicationDisplayName") + return { + "actor": actor, + "activityDateTime": data["value"][0]["activityDateTime"], + "activityOperationType": data["value"][0]["activityOperationType"], + "activityResult": data["value"][0]["activityResult"], + } diff --git a/src/IntuneCD/intunecdlib/process_audit_data.py b/src/IntuneCD/intunecdlib/process_audit_data.py new file mode 100644 index 00000000..618f770f --- /dev/null +++ b/src/IntuneCD/intunecdlib/process_audit_data.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +This module processes the audit data from Intune. +""" + +import subprocess + +from .logger import log + + +def _git_installed(): + cmd = ["git", "--version"] + log("_git_installed", "Running command git --version to check if git is installed.") + git_version = subprocess.run(cmd, capture_output=True, text=True, check=False) + if git_version.returncode != 0: + log("_git_installed", "Git is not installed.") + return False + + log("_git_installed", "Git is installed.") + return True + + +def _configure_git(audit_data, path): + cmd = [ + "git", + "-C", + path, + "config", + "--local", + "user.email", + f"{audit_data['actor']}", + ] + log( + "_configure_git", + f"Running command {cmd} to configure git user email to {audit_data['actor']}.", + ) + subprocess.run( + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False + ) + + +def _check_if_git_repo(path, file): + cmd = ["git", "-C", path, "rev-parse", "--is-inside-work-tree"] + log("_check_if_git_repo", f"Path is set to {path} and file is set to {file}.") + log( + "_check_if_git_repo", + f"Running command git command {cmd} to determine if the path is a git repo.", + ) + git_status = subprocess.run(cmd, capture_output=True, text=True, check=False) + + if git_status.stdout.strip() == "true": + log("_check_if_git_repo", "Path is a git repo.") + return True + + log("_check_if_git_repo", "Path is not a git repo.") + return False + + +def _git_check_modified(path, file): + cmd = ["git", "-C", path, "diff", "--name-only", f"{file}"] + log( + "_git_check_modified", + f"Running command {cmd} to check if {file} has been modified.", + ) + result = subprocess.run(cmd, capture_output=True, text=True, check=False) + return result.stdout + + +def _git_check_new_file(path, file): + # check if it is a new file + cmd = ["git", "-C", path, "ls-files", "--error-unmatch", f"{file}"] + log( + "_git_check_new_file", + f"Running command {cmd} to check if {file} is a new file.", + ) + new_file_result = subprocess.run(cmd, capture_output=True, text=True, check=False) + # check if "did not match any file(s) known to git" is in the stderr + if "did not match any file(s) known to git" in new_file_result.stderr: + return True + + return False + + +def _git_commit_changes(audit_data, path, file): + # commit the changes + cmd = ["git", "-C", path, "add", f"{file}"] + log("_git_commit_changes", f"Running command {cmd} to add {file} to the git repo.") + subprocess.run( + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False + ) + log("_git_commit_changes", f"Committing the changes to {file}.") + cmd = [ + "git", + "-C", + path, + "commit", + "-m", + ( + f"Updated by {audit_data['actor']} on {audit_data['activityDateTime']}, " + f"change type: {audit_data['activityOperationType']}, result: {audit_data['activityResult']}" + ), + ] + + commit = subprocess.run( + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False + ) + + if commit.returncode == 0: + log("_git_commit_changes", "Commit was successful.") + else: + log("_git_commit_changes", f"Commit was not successful, error: {commit.stderr}") + + +def process_audit_data(audit_data, path, file): + """ + Processes the audit data from Intune. + + :param audit_data: The audit data to process. + :return: The processed audit data. + """ + + log("process_audit_data", f"Processing audit data for {file} in path {path}.") + # determine if the path we are using is a git repo + git_repo = _check_if_git_repo(path, file) + + # Commit the changes + if git_repo: + # check if git is installed + if not _git_installed(): + return + # configure git + _configure_git(audit_data, path) + # check if file has been modified + result = _git_check_modified(path, file) + + if not result: + file_not_found = _git_check_new_file(path, file) + + if result or file_not_found: + # commit the changes + _git_commit_changes(audit_data, path, file) + else: + log( + "process_audit_data", + f"{file} has not been modified, no changes to commit.", + ) + + log("process_audit_data", "Audit data has been processed.") diff --git a/src/IntuneCD/run_backup.py b/src/IntuneCD/run_backup.py index b57d8d28..ffc4e12b 100644 --- a/src/IntuneCD/run_backup.py +++ b/src/IntuneCD/run_backup.py @@ -191,6 +191,11 @@ def start(): parser.add_argument( "-v", "--verbose", help="Prints verbose output", action="store_true" ) + parser.add_argument( + "--audit", + help="When set, the script will process the audit data from Intune and commit the changes to the git repo using the name of the user who made the change and the date and time of the change", + action="store_true", + ) args = parser.parse_args() diff --git a/tests/Backup/Intune/test_backup_apns.py b/tests/Backup/Intune/test_backup_apns.py index 53536d38..e2706476 100644 --- a/tests/Backup/Intune/test_backup_apns.py +++ b/tests/Backup/Intune/test_backup_apns.py @@ -58,7 +58,7 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.makeapirequest.return_value = self.apns - self.count = savebackup(self.directory.path, "yaml", self.token) + self.count = savebackup(self.directory.path, "yaml", False, self.token) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: data = json.dumps(yaml.safe_load(f)) @@ -72,7 +72,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.makeapirequest.return_value = self.apns - self.count = savebackup(self.directory.path, "json", self.token) + self.count = savebackup(self.directory.path, "json", False, self.token) with open(self.saved_path + "json", "r", encoding="utf-8") as f: saved_data = json.load(f) @@ -85,7 +85,7 @@ def test_backup_with_no_return_data(self): """The count should be 0 if no data is returned.""" self.makeapirequest.return_value = None - self.count = savebackup(self.directory.path, "json", self.token) + self.count = savebackup(self.directory.path, "json", False, self.token) self.assertEqual(0, self.count["config_count"]) diff --git a/tests/Backup/Intune/test_backup_appConfiguration.py b/tests/Backup/Intune/test_backup_appConfiguration.py index ad28f66b..768d03b8 100644 --- a/tests/Backup/Intune/test_backup_appConfiguration.py +++ b/tests/Backup/Intune/test_backup_appConfiguration.py @@ -103,7 +103,13 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, "", self.append_id + self.directory.path, + "yaml", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -118,7 +124,13 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -132,7 +144,13 @@ def test_backup_with_no_returned_data(self): """The count should be 0 if no data is returned.""" self.makeapirequest.side_effect = [{"value": []}] self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -146,6 +164,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -154,7 +173,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, "", True + self.directory.path, "yaml", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_appProtection.py b/tests/Backup/Intune/test_backup_appProtection.py index c5f9d5bc..24b39f93 100644 --- a/tests/Backup/Intune/test_backup_appProtection.py +++ b/tests/Backup/Intune/test_backup_appProtection.py @@ -93,7 +93,13 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, "", self.append_id + self.directory.path, + "yaml", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -108,7 +114,13 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -127,7 +139,13 @@ def test_backup_targetedManagedAppConfiguration(self): ] } self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -138,7 +156,13 @@ def test_backup_targetedAppManagementLevels(self): self.expected_data["targetedAppManagementLevels"] = "test" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open( @@ -155,7 +179,13 @@ def test_backup_with_no_returned_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -169,6 +199,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -176,7 +207,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_appleEnrollmentProfile.py b/tests/Backup/Intune/test_backup_appleEnrollmentProfile.py index 4e5edd34..17efeea3 100644 --- a/tests/Backup/Intune/test_backup_appleEnrollmentProfile.py +++ b/tests/Backup/Intune/test_backup_appleEnrollmentProfile.py @@ -83,7 +83,7 @@ def test_backup_yml(self): self.makeapirequest.return_value = self.token_response self.batch_request.return_value = self.batch_intune self.count = savebackup( - self.directory.path, "yaml", self.token, "", self.append_id + self.directory.path, "yaml", self.token, "", self.append_id, False ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -101,7 +101,7 @@ def test_backup_json(self): self.makeapirequest.return_value = self.token_response self.batch_request.return_value = self.batch_intune self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id + self.directory.path, "json", self.token, "", self.append_id, False ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -119,7 +119,7 @@ def test_backup_with_no_return_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id + self.directory.path, "json", self.token, "", self.append_id, False ) self.assertEqual(0, self.count["config_count"]) @@ -129,7 +129,7 @@ def test_backup_with_prefix(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.token, "test", self.append_id + self.directory.path, "json", self.token, "test", self.append_id, False ) self.assertEqual(0, self.count["config_count"]) @@ -139,7 +139,9 @@ def test_backup_append_id(self): self.makeapirequest.return_value = self.token_response self.batch_request.return_value = self.batch_intune - self.count = savebackup(self.directory.path, "json", self.token, "", True) + self.count = savebackup( + self.directory.path, "json", self.token, "", True, False + ) self.assertTrue( Path( diff --git a/tests/Backup/Intune/test_backup_applications.py b/tests/Backup/Intune/test_backup_applications.py index 1b047b4a..70a8aefc 100644 --- a/tests/Backup/Intune/test_backup_applications.py +++ b/tests/Backup/Intune/test_backup_applications.py @@ -77,7 +77,7 @@ def test_backup_ios_vpp_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertTrue(Path(self.directory.path + "/Applications/iOS").exists()) @@ -95,7 +95,7 @@ def test_backup_macOS_vpp_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertTrue(Path(self.directory.path + "/Applications/macOS").exists()) @@ -117,7 +117,7 @@ def test_backup_vpp_app_exclude_licensecount(self): self.exclude = ["VPPusedLicenseCount"] self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) app_data = json.load( @@ -137,7 +137,7 @@ def test_backup_win32_lob_app_and_displayVersion(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertTrue(Path(self.directory.path + "/Applications/Windows").exists()) @@ -156,7 +156,7 @@ def test_backup_win32_lob_app_no_displayVersion(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertTrue(Path(self.directory.path + "/Applications/Windows").exists()) @@ -175,7 +175,7 @@ def test_backup_msi_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertTrue(Path(self.directory.path + "/Applications/Windows").exists()) @@ -195,7 +195,7 @@ def test_backup_android_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertTrue(Path(self.directory.path + "/Applications/Android").exists()) @@ -214,7 +214,7 @@ def test_backup_microsoft_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertTrue(Path(self.directory.path + "/Applications/Windows").exists()) @@ -234,7 +234,7 @@ def test_backup_office_suite_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertTrue( @@ -255,7 +255,7 @@ def test_backup_web_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertTrue(Path(self.directory.path + "/Applications/Web App").exists()) @@ -273,7 +273,7 @@ def test_backup_other_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertTrue(Path(self.directory.path + "/Applications/macOS").exists()) @@ -288,7 +288,7 @@ def test_backup_with_no_returned_data(self): """The count should be 0 if no data is returned.""" self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertEqual(0, self.count["config_count"]) @@ -299,7 +299,7 @@ def test_backup_append_id(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, True + self.directory.path, "json", self.exclude, self.token, True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_assignmentFilter.py b/tests/Backup/Intune/test_backup_assignmentFilter.py index e7288008..fd48dc5f 100644 --- a/tests/Backup/Intune/test_backup_assignmentFilter.py +++ b/tests/Backup/Intune/test_backup_assignmentFilter.py @@ -57,7 +57,7 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.token, "", self.append_id + self.directory.path, "yaml", self.token, "", self.append_id, False ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -72,7 +72,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id + self.directory.path, "json", self.token, "", self.append_id, False ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -87,7 +87,7 @@ def test_backup_with_no_return_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id + self.directory.path, "json", self.token, "", self.append_id, False ) self.assertEqual(0, self.count["config_count"]) @@ -96,14 +96,16 @@ def test_backup_with_prefix(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.token, "test", self.append_id + self.directory.path, "json", self.token, "test", self.append_id, False ) self.assertEqual(0, self.count["config_count"]) def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "json", self.token, "", True) + self.count = savebackup( + self.directory.path, "json", self.token, "", True, False + ) self.assertTrue( Path(f"{self.directory.path}/Filters/macOS - Model__0.json").exists() diff --git a/tests/Backup/Intune/test_backup_compliance.py b/tests/Backup/Intune/test_backup_compliance.py index 77271e41..496edfb8 100644 --- a/tests/Backup/Intune/test_backup_compliance.py +++ b/tests/Backup/Intune/test_backup_compliance.py @@ -89,7 +89,13 @@ def test_backup_yml(self): output = "yaml" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -107,7 +113,13 @@ def test_backup_json(self): output = "json" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -124,7 +136,13 @@ def test_backup_with_no_returned_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -139,6 +157,7 @@ def test_backup_with_prefix(self): self.token, "test", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -146,7 +165,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_compliancePartner.py b/tests/Backup/Intune/test_backup_compliancePartner.py index 49d62361..16a487ed 100644 --- a/tests/Backup/Intune/test_backup_compliancePartner.py +++ b/tests/Backup/Intune/test_backup_compliancePartner.py @@ -70,7 +70,7 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, self.append_id + self.directory.path, "yaml", self.exclude, self.token, self.append_id, False ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -87,7 +87,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -104,7 +104,7 @@ def test_backup_with_no_return_data(self): self.makeapirequest.return_value = {"value": [{"partnerState": "unknown"}]} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertEqual(0, self.count["config_count"]) @@ -112,7 +112,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, True + self.directory.path, "json", self.exclude, self.token, True, False ) self.assertTrue( @@ -127,7 +127,7 @@ def test_backup_exclude_lastHeartbeatDateTime(self): self.exclude.append("CompliancePartnerHeartbeat") self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: diff --git a/tests/Backup/Intune/test_backup_configurationPolicies.py b/tests/Backup/Intune/test_backup_configurationPolicies.py index f7acab5b..72dd9938 100644 --- a/tests/Backup/Intune/test_backup_configurationPolicies.py +++ b/tests/Backup/Intune/test_backup_configurationPolicies.py @@ -128,7 +128,13 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, "", self.append_id + self.directory.path, + "yaml", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -143,7 +149,13 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -158,7 +170,13 @@ def test_backup_with_no_returned_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -173,6 +191,7 @@ def test_backup_with_prefix(self): self.token, "test", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -180,7 +199,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_customAttributeShellScript.py b/tests/Backup/Intune/test_backup_customAttributeShellScript.py index cc28e4a1..0f12fe3a 100644 --- a/tests/Backup/Intune/test_backup_customAttributeShellScript.py +++ b/tests/Backup/Intune/test_backup_customAttributeShellScript.py @@ -81,7 +81,13 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, "", self.append_id + self.directory.path, + "yaml", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -96,7 +102,13 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -110,7 +122,13 @@ def test_script_is_created(self): """The folder should be created and a .ps1 file should be created.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertTrue(f"{self.directory.path}/Custom Attributes/Script Data") @@ -122,7 +140,13 @@ def test_backup_with_no_returned_data(self): self.batch_request.return_value = [] self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -137,6 +161,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -145,7 +170,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_deviceCategories.py b/tests/Backup/Intune/test_backup_deviceCategories.py index e1284589..d5dc98f0 100644 --- a/tests/Backup/Intune/test_backup_deviceCategories.py +++ b/tests/Backup/Intune/test_backup_deviceCategories.py @@ -54,7 +54,7 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.token, "", self.append_id + self.directory.path, "yaml", self.token, "", self.append_id, False ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -69,7 +69,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id + self.directory.path, "json", self.token, "", self.append_id, False ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -84,7 +84,7 @@ def test_backup_with_no_return_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id + self.directory.path, "json", self.token, "", self.append_id, False ) self.assertEqual(0, self.count["config_count"]) @@ -93,14 +93,16 @@ def test_backup_with_prefix(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.token, "test", self.append_id + self.directory.path, "json", self.token, "test", self.append_id, False ) self.assertEqual(0, self.count["config_count"]) def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "json", self.token, "", True) + self.count = savebackup( + self.directory.path, "json", self.token, "", True, False + ) self.assertTrue( Path( diff --git a/tests/Backup/Intune/test_backup_deviceManagementSettings.py b/tests/Backup/Intune/test_backup_deviceManagementSettings.py index 051c290f..7086fdfb 100644 --- a/tests/Backup/Intune/test_backup_deviceManagementSettings.py +++ b/tests/Backup/Intune/test_backup_deviceManagementSettings.py @@ -65,7 +65,7 @@ def tearDown(self): def test_backup_yml(self, _, __): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "yaml", self.token) + self.count = savebackup(self.directory.path, "yaml", False, self.token) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: data = json.dumps(yaml.safe_load(f)) @@ -80,7 +80,7 @@ def test_backup_yml(self, _, __): def test_backup_json(self, _, __): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "json", self.token) + self.count = savebackup(self.directory.path, "json", False, self.token) with open(self.saved_path + "json", "r", encoding="utf-8") as f: self.saved_data = json.load(f) diff --git a/tests/Backup/Intune/test_backup_enrollmentConfigurations.py b/tests/Backup/Intune/test_backup_enrollmentConfigurations.py index 1f0383cc..ad5cee08 100644 --- a/tests/Backup/Intune/test_backup_enrollmentConfigurations.py +++ b/tests/Backup/Intune/test_backup_enrollmentConfigurations.py @@ -79,7 +79,13 @@ def test_backup_yml(self): """Test that the backup is saved as yml. And that the data is correct.""" output = "yaml" savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(f"{self.saved_path}yaml", "r", encoding="utf-8") as file: data = yaml.safe_load(file) @@ -89,7 +95,13 @@ def test_backup_json(self): """Test that the backup is saved as json. And that the data is correct.""" output = "json" savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(f"{self.saved_path}json", "r", encoding="utf-8") as file: data = yaml.safe_load(file) @@ -102,7 +114,13 @@ def test_backup_skip_ESP(self): "@odata.type" ] = "#microsoft.graph.windows10EnrollmentCompletionPageConfiguration" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, count["config_count"]) @@ -112,7 +130,13 @@ def test_backup_with_no_returned_data(self): self.makeapirequest.side_effect = [{"value": []}] self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -127,6 +151,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -134,7 +159,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_groupPolicyConfiguration.py b/tests/Backup/Intune/test_backup_groupPolicyConfiguration.py index b0363877..1cb59b1a 100644 --- a/tests/Backup/Intune/test_backup_groupPolicyConfiguration.py +++ b/tests/Backup/Intune/test_backup_groupPolicyConfiguration.py @@ -98,7 +98,13 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, "", self.append_id + self.directory.path, + "yaml", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -115,7 +121,13 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -132,7 +144,13 @@ def test_backup_with_no_returned_data(self): self.makeapirequest.side_effect = [{"value": []}] self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -147,6 +165,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -154,7 +173,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_managedGPlay.py b/tests/Backup/Intune/test_backup_managedGPlay.py index f7ebe408..9223fcb1 100644 --- a/tests/Backup/Intune/test_backup_managedGPlay.py +++ b/tests/Backup/Intune/test_backup_managedGPlay.py @@ -54,7 +54,7 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, self.append_id + self.directory.path, "yaml", self.exclude, self.token, self.append_id, False ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -69,7 +69,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -84,7 +84,7 @@ def test_backup_with_no_return_data(self): self.makeapirequest.return_value = None self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertEqual(0, self.count["config_count"]) @@ -92,7 +92,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, True + self.directory.path, "json", self.exclude, self.token, True, False ) self.assertTrue( @@ -106,7 +106,7 @@ def test_backup_exclude_lastAppSyncDateTime(self): self.exclude.append("GPlaySyncTime") self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: diff --git a/tests/Backup/Intune/test_backup_managementIntents.py b/tests/Backup/Intune/test_backup_managementIntents.py index 37adb7a4..c99fd661 100644 --- a/tests/Backup/Intune/test_backup_managementIntents.py +++ b/tests/Backup/Intune/test_backup_managementIntents.py @@ -99,7 +99,13 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, "", self.append_id + self.directory.path, + "yaml", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -116,7 +122,13 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -133,7 +145,13 @@ def test_backup_with_no_returned_data(self): self.batch_intent.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -148,6 +166,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -155,7 +174,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_managementPartner.py b/tests/Backup/Intune/test_backup_managementPartner.py index 1683c470..d4a537ff 100644 --- a/tests/Backup/Intune/test_backup_managementPartner.py +++ b/tests/Backup/Intune/test_backup_managementPartner.py @@ -52,7 +52,9 @@ def tearDown(self): def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "yaml", self.token, self.append_id) + self.count = savebackup( + self.directory.path, "yaml", self.token, self.append_id, False + ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: data = json.dumps(yaml.safe_load(f)) @@ -67,7 +69,9 @@ def test_backup_yml(self): def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "json", self.token, self.append_id) + self.count = savebackup( + self.directory.path, "json", self.token, self.append_id, False + ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: self.saved_data = json.load(f) @@ -82,13 +86,15 @@ def test_backup_with_no_return_data(self): """The count should be 0 if no data is returned.""" self.makeapirequest.return_value = {"value": [{"isConfigured": False}]} - self.count = savebackup(self.directory.path, "json", self.token, self.append_id) + self.count = savebackup( + self.directory.path, "json", self.token, self.append_id, False + ) self.assertEqual(0, self.count["config_count"]) def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "json", self.token, True) + self.count = savebackup(self.directory.path, "json", self.token, True, False) self.assertTrue( Path( diff --git a/tests/Backup/Intune/test_backup_notificationTemplate.py b/tests/Backup/Intune/test_backup_notificationTemplate.py index 343b2f99..428a5b4c 100644 --- a/tests/Backup/Intune/test_backup_notificationTemplate.py +++ b/tests/Backup/Intune/test_backup_notificationTemplate.py @@ -92,7 +92,7 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.token, "", self.append_id + self.directory.path, "yaml", self.token, "", self.append_id, False ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -111,7 +111,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id + self.directory.path, "json", self.token, "", self.append_id, False ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -130,7 +130,7 @@ def test_backup_with_no_return_data(self): self.makeapirequest.side_effect = [{"value": []}] self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id + self.directory.path, "json", self.token, "", self.append_id, False ) self.assertEqual(0, self.count["config_count"]) @@ -138,14 +138,16 @@ def test_backup_with_prefix(self): """The count should be 0 if no data is returned.""" self.count = savebackup( - self.directory.path, "json", self.token, "test1", self.append_id + self.directory.path, "json", self.token, "test1", self.append_id, False ) self.assertEqual(0, self.count["config_count"]) def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "json", self.token, "", True) + self.count = savebackup( + self.directory.path, "json", self.token, "", True, False + ) self.assertTrue( Path( diff --git a/tests/Backup/Intune/test_backup_powershellScripts.py b/tests/Backup/Intune/test_backup_powershellScripts.py index 987e5edc..142246e1 100644 --- a/tests/Backup/Intune/test_backup_powershellScripts.py +++ b/tests/Backup/Intune/test_backup_powershellScripts.py @@ -81,7 +81,13 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, "", self.append_id + self.directory.path, + "yaml", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -96,7 +102,13 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -110,7 +122,13 @@ def test_script_is_created(self): """The script data folder should be created and a .ps1 file should be created.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertTrue( @@ -124,7 +142,13 @@ def test_backup_with_no_returned_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -139,6 +163,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -146,7 +171,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_proactiveRemediation.py b/tests/Backup/Intune/test_backup_proactiveRemediation.py index f389b8f0..8c3f9fc8 100644 --- a/tests/Backup/Intune/test_backup_proactiveRemediation.py +++ b/tests/Backup/Intune/test_backup_proactiveRemediation.py @@ -82,7 +82,13 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, "", self.append_id + self.directory.path, + "yaml", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -97,7 +103,13 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -111,7 +123,13 @@ def test_detection_script_is_created(self): """The folder should be created and a .ps1 file should be created.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertTrue(f"{self.directory.path}/Proactive Remediations/Script Data") @@ -121,7 +139,13 @@ def test_remediation_script_is_created(self): """The folder should be created and a .ps1 file should be created.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertTrue(f"{self.directory.path}/Proactive Remediations/Script Data") @@ -141,6 +165,7 @@ def test_publisher_is_microsoft(self): self.token, "", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -159,6 +184,7 @@ def test_backup_with_no_returned_data(self): self.token, "", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -173,6 +199,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -180,7 +207,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_profiles.py b/tests/Backup/Intune/test_backup_profiles.py index 1562ca51..8a56c6cc 100644 --- a/tests/Backup/Intune/test_backup_profiles.py +++ b/tests/Backup/Intune/test_backup_profiles.py @@ -72,6 +72,7 @@ def test_backup_macOS_custom_profile(self): "", self.append_id, False, + False, ) self.assertTrue( @@ -109,6 +110,7 @@ def test_backup_ios_custom_profile(self): "", self.append_id, False, + False, ) self.assertTrue( @@ -161,6 +163,7 @@ def test_backup_windows_custom_profile_encrypted(self): "", self.append_id, False, + False, ) self.assertTrue( @@ -208,6 +211,7 @@ def test_backup_windows_custom_profile_not_encrypted(self): "", self.append_id, False, + False, ) self.assertTrue( @@ -272,6 +276,7 @@ def test_backup_non_custom_profile(self): "", self.append_id, False, + False, ) self.assertTrue( @@ -292,6 +297,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -308,7 +314,14 @@ def test_backup_append_id(self): } self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + False, + False, ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_remoteAssistancePartner.py b/tests/Backup/Intune/test_backup_remoteAssistancePartner.py index 9e2cd794..cca81796 100644 --- a/tests/Backup/Intune/test_backup_remoteAssistancePartner.py +++ b/tests/Backup/Intune/test_backup_remoteAssistancePartner.py @@ -45,7 +45,9 @@ def tearDown(self): def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "yaml", self.token, self.append_id) + self.count = savebackup( + self.directory.path, "yaml", self.token, self.append_id, False + ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: data = json.dumps(yaml.safe_load(f)) @@ -62,7 +64,9 @@ def test_backup_yml(self): def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "json", self.token, self.append_id) + self.count = savebackup( + self.directory.path, "json", self.token, self.append_id, False + ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: self.saved_data = json.load(f) @@ -81,20 +85,24 @@ def test_onboarding_status_not_onboarded(self): self.makeapirequest.return_value = { "value": [{"onboardingStatus": "notOnboarded"}] } - self.count = savebackup(self.directory.path, "json", self.token, self.append_id) + self.count = savebackup( + self.directory.path, "json", self.token, self.append_id, False + ) self.assertEqual(0, self.count["config_count"]) def test_backup_with_no_return_data(self): """The count should be 0 if no data is returned.""" self.makeapirequest.return_value = {"value": []} - self.count = savebackup(self.directory.path, "json", self.token, self.append_id) + self.count = savebackup( + self.directory.path, "json", self.token, self.append_id, False + ) self.assertEqual(0, self.count["config_count"]) def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "json", self.token, True) + self.count = savebackup(self.directory.path, "json", self.token, True, False) self.assertTrue( Path( diff --git a/tests/Backup/Intune/test_backup_roles.py b/tests/Backup/Intune/test_backup_roles.py index e48362dc..8721cbcb 100644 --- a/tests/Backup/Intune/test_backup_roles.py +++ b/tests/Backup/Intune/test_backup_roles.py @@ -113,7 +113,7 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", "", self.token, self.append_id + self.directory.path, "yaml", "", self.token, self.append_id, False ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -128,7 +128,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", "", self.token, self.append_id + self.directory.path, "json", "", self.token, self.append_id, False ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -143,14 +143,16 @@ def test_backup_with_no_return_data(self): self.makeapirequest.side_effect = [{"value": []}, {"value": []}, {"value": []}] self.count = savebackup( - self.directory.path, "json", "", self.token, self.append_id + self.directory.path, "json", "", self.token, self.append_id, False ) self.assertEqual(0, self.count["config_count"]) def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "json", "", self.token, True) + self.count = savebackup( + self.directory.path, "json", "", self.token, True, False + ) self.assertTrue(Path(f"{self.directory.path}/Roles/test__0.json").exists()) diff --git a/tests/Backup/Intune/test_backup_scopeTags.py b/tests/Backup/Intune/test_backup_scopeTags.py index bdc52f44..846e398f 100644 --- a/tests/Backup/Intune/test_backup_scopeTags.py +++ b/tests/Backup/Intune/test_backup_scopeTags.py @@ -73,7 +73,7 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, self.append_id + self.directory.path, "yaml", self.exclude, self.token, self.append_id, False ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -88,7 +88,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -103,7 +103,7 @@ def test_backup_with_no_returned_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id + self.directory.path, "json", self.exclude, self.token, self.append_id, False ) self.assertEqual(0, self.count["config_count"]) @@ -111,7 +111,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, True + self.directory.path, "json", self.exclude, self.token, True, False ) self.assertTrue(Path(f"{self.directory.path}/Scope Tags/test__1.json").exists()) diff --git a/tests/Backup/Intune/test_backup_shellScripts.py b/tests/Backup/Intune/test_backup_shellScripts.py index fe466569..3f65fa45 100644 --- a/tests/Backup/Intune/test_backup_shellScripts.py +++ b/tests/Backup/Intune/test_backup_shellScripts.py @@ -81,7 +81,13 @@ def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, "", self.append_id + self.directory.path, + "yaml", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -96,7 +102,13 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -110,7 +122,13 @@ def test_script_is_created(self): """The folder should be created and a .ps1 file should be created.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertTrue(f"{self.directory.path}/Scripts/Shell/Script Data") @@ -122,7 +140,13 @@ def test_backup_with_no_returned_data(self): self.batch_request.return_value = [] self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -137,6 +161,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -144,7 +169,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_vppTokens.py b/tests/Backup/Intune/test_backup_vppTokens.py index cbf33588..cd3c47e0 100644 --- a/tests/Backup/Intune/test_backup_vppTokens.py +++ b/tests/Backup/Intune/test_backup_vppTokens.py @@ -41,7 +41,9 @@ def tearDown(self): def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "yaml", self.token, self.append_id) + self.count = savebackup( + self.directory.path, "yaml", self.token, self.append_id, False + ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: data = json.dumps(yaml.safe_load(f)) @@ -54,7 +56,9 @@ def test_backup_yml(self): def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "json", self.token, self.append_id) + self.count = savebackup( + self.directory.path, "json", self.token, self.append_id, False + ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: self.saved_data = json.load(f) @@ -67,13 +71,15 @@ def test_backup_with_no_return_data(self): """The count should be 0 if no data is returned.""" self.makeapirequest.return_value = {"value": []} - self.count = savebackup(self.directory.path, "json", self.token, self.append_id) + self.count = savebackup( + self.directory.path, "json", self.token, self.append_id, False + ) self.assertEqual(0, self.count["config_count"]) def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "json", self.token, True) + self.count = savebackup(self.directory.path, "json", self.token, True, False) self.assertTrue( Path(f"{self.directory.path}/Apple VPP Tokens/test__0.json").exists() diff --git a/tests/Backup/Intune/test_backup_windowsDriverUpdates.py b/tests/Backup/Intune/test_backup_windowsDriverUpdates.py index 6da090a1..56c2ecda 100644 --- a/tests/Backup/Intune/test_backup_windowsDriverUpdates.py +++ b/tests/Backup/Intune/test_backup_windowsDriverUpdates.py @@ -62,7 +62,13 @@ def test_backup_yml(self): output = "yaml" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -78,7 +84,13 @@ def test_backup_json(self): output = "json" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -93,7 +105,13 @@ def test_backup_with_no_returned_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -108,6 +126,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -115,7 +134,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_windowsEnrollmentProfile.py b/tests/Backup/Intune/test_backup_windowsEnrollmentProfile.py index 3402e6c6..4bf6bd72 100644 --- a/tests/Backup/Intune/test_backup_windowsEnrollmentProfile.py +++ b/tests/Backup/Intune/test_backup_windowsEnrollmentProfile.py @@ -62,7 +62,13 @@ def test_backup_yml(self): output = "yaml" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -78,7 +84,13 @@ def test_backup_json(self): output = "json" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -93,7 +105,13 @@ def test_backup_with_no_returned_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -108,6 +126,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -115,7 +134,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_windowsFeatureUpdates.py b/tests/Backup/Intune/test_backup_windowsFeatureUpdates.py index 0f3ab519..a5b30e09 100644 --- a/tests/Backup/Intune/test_backup_windowsFeatureUpdates.py +++ b/tests/Backup/Intune/test_backup_windowsFeatureUpdates.py @@ -62,7 +62,13 @@ def test_backup_yml(self): output = "yaml" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -78,7 +84,13 @@ def test_backup_json(self): output = "json" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -93,7 +105,13 @@ def test_backup_with_no_returned_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -108,6 +126,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -115,7 +134,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_windowsQualityUpdates.py b/tests/Backup/Intune/test_backup_windowsQualityUpdates.py index e6e62960..e9ae7367 100644 --- a/tests/Backup/Intune/test_backup_windowsQualityUpdates.py +++ b/tests/Backup/Intune/test_backup_windowsQualityUpdates.py @@ -62,7 +62,13 @@ def test_backup_yml(self): output = "yaml" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -78,7 +84,13 @@ def test_backup_json(self): output = "json" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -93,7 +105,13 @@ def test_backup_with_no_returned_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -108,6 +126,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -115,7 +134,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, False ) self.assertTrue( From b33937e2ee015fe998afd5f668138b587051f279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Sat, 24 Feb 2024 15:27:59 +0100 Subject: [PATCH 02/35] bump to 2.2.0.beta1 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 0dc7b0b8..dfd528f0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = IntuneCD -version = 2.1.2 +version = 2.2.0.beta1 author = Tobias Almén author_email = almenscorner@outlook.com description = Tool to backup and update configurations in Intune From 39fd6a509b3981fdaf256f3aa4b933c613fb622f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Sat, 24 Feb 2024 16:07:20 +0100 Subject: [PATCH 03/35] configure name in git --- src/IntuneCD/intunecdlib/process_audit_data.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/IntuneCD/intunecdlib/process_audit_data.py b/src/IntuneCD/intunecdlib/process_audit_data.py index 618f770f..89dfc0c6 100644 --- a/src/IntuneCD/intunecdlib/process_audit_data.py +++ b/src/IntuneCD/intunecdlib/process_audit_data.py @@ -40,6 +40,21 @@ def _configure_git(audit_data, path): cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False ) + # configure the user name for git commits + cmd = [ + "git", + "-C", + path, + "config", + "--local", + "user.name", + f"{audit_data['actor']}", + ] + log("_configure_git", f"Running command {cmd} to configure git user name.") + subprocess.run( + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False + ) + def _check_if_git_repo(path, file): cmd = ["git", "-C", path, "rev-parse", "--is-inside-work-tree"] From 56b9baf7b105ec2a276c8c5d94a3a1b6067803ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Sat, 24 Feb 2024 16:07:33 +0100 Subject: [PATCH 04/35] bump to 2.2.0-beta2 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index dfd528f0..252f81f1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = IntuneCD -version = 2.2.0.beta1 +version = 2.2.0.beta2 author = Tobias Almén author_email = almenscorner@outlook.com description = Tool to backup and update configurations in Intune From d4cfbb51f8ce3c78f04defda7bd8bb9a3040e6ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:29:18 +0100 Subject: [PATCH 05/35] change to bulk get audit logs --- .../backup/Intune/backup_AppProtection.py | 15 ++-- src/IntuneCD/backup/Intune/backup_apns.py | 20 +++-- .../backup/Intune/backup_appConfiguration.py | 17 ++-- .../Intune/backup_appleEnrollmentProfile.py | 17 ++-- .../backup/Intune/backup_applications.py | 19 +++-- .../backup/Intune/backup_assignmentFilters.py | 17 ++-- .../backup/Intune/backup_compliance.py | 15 ++-- .../backup/Intune/backup_compliancePartner.py | 15 ++-- .../Intune/backup_configurationPolicies.py | 15 ++-- .../backup_customAttributeShellScript.py | 15 ++-- .../backup/Intune/backup_deviceCategories.py | 18 ++-- .../Intune/backup_deviceManagementSettings.py | 24 +++--- .../Intune/backup_enrollmentConfigurations.py | 15 ++-- .../Intune/backup_groupPolicyConfiguration.py | 15 ++-- .../backup/Intune/backup_managedGPlay.py | 19 +++-- .../backup/Intune/backup_managementIntents.py | 17 ++-- .../backup/Intune/backup_managementPartner.py | 15 ++-- .../Intune/backup_notificationTemplate.py | 15 ++-- .../backup/Intune/backup_powershellScripts.py | 17 ++-- .../Intune/backup_proactiveRemediation.py | 18 ++-- src/IntuneCD/backup/Intune/backup_profiles.py | 43 ++++------ .../Intune/backup_remoteAssistancePartner.py | 15 ++-- src/IntuneCD/backup/Intune/backup_roles.py | 15 ++-- .../backup/Intune/backup_scopeTags.py | 16 ++-- .../backup/Intune/backup_shellScripts.py | 15 ++-- .../backup/Intune/backup_vppTokens.py | 15 ++-- .../Intune/backup_windowsDriverUpdates.py | 15 ++-- .../Intune/backup_windowsEnrollmentProfile.py | 15 ++-- .../Intune/backup_windowsFeatureUpdates.py | 15 ++-- .../Intune/backup_windowsQualityUpdates.py | 15 ++-- src/IntuneCD/intunecdlib/graph_request.py | 48 +++++++---- .../intunecdlib/process_audit_data.py | 83 ++++++++++++++++--- 32 files changed, 365 insertions(+), 283 deletions(-) diff --git a/src/IntuneCD/backup/Intune/backup_AppProtection.py b/src/IntuneCD/backup/Intune/backup_AppProtection.py index 36bdd4e0..204e0e57 100644 --- a/src/IntuneCD/backup/Intune/backup_AppProtection.py +++ b/src/IntuneCD/backup/Intune/backup_AppProtection.py @@ -29,12 +29,16 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "App Protection/" data = makeapirequest(ENDPOINT, token) assignment_responses = batch_assignment( data, "deviceAppManagement/", "/assignments", token, app_protection=True ) + if audit: + graph_filter = "componentName eq 'ManagedAppProtection'" + audit_data = makeAuditRequest(graph_filter, token) # If profile is ManagedAppConfiguration, skip to next for profile in data["value"]: @@ -77,13 +81,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_apns.py b/src/IntuneCD/backup/Intune/backup_apns.py index 11003639..21219d72 100644 --- a/src/IntuneCD/backup/Intune/backup_apns.py +++ b/src/IntuneCD/backup/Intune/backup_apns.py @@ -28,9 +28,12 @@ def savebackup(path, output, audit, token): """ results = {"config_count": 0, "outputs": []} - + audit_data = None configpath = path + "/" + "Apple Push Notification/" data = makeapirequest(ENDPOINT, token) + if audit: + graph_filter = "resources/any(s:s/auditResourceType eq 'Microsoft.Management.Services.Api.ApplePushNotificationCertificate')" + audit_data = makeAuditRequest(graph_filter, token) if data: results["config_count"] += 1 @@ -44,14 +47,13 @@ def savebackup(path, output, audit, token): results["outputs"].append(fname) - if audit: - graph_filter = "resources/any(s:s/auditResourceType eq 'Microsoft.Management.Services.Api.ApplePushNotificationCertificate')" - audit_data = makeAuditRequest( - "", - graph_filter, - token, + if audit_data: + compare_data = { + "type": "auditResourceType", + "value": "Microsoft.Management.Services.Api.ApplePushNotificationCertificate", + } + process_audit_data( + audit_data, path, compare_data, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_appConfiguration.py b/src/IntuneCD/backup/Intune/backup_appConfiguration.py index d4ebda50..4064a811 100644 --- a/src/IntuneCD/backup/Intune/backup_appConfiguration.py +++ b/src/IntuneCD/backup/Intune/backup_appConfiguration.py @@ -35,8 +35,12 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "App Configuration/" data = makeapirequest(ENDPOINT, token) + if audit: + graph_filter = "componentName eq 'MobileAppConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) if data["value"]: assignment_responses = batch_assignment( @@ -91,15 +95,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data( - audit_data, path, f"{configpath}{fname}.{output}" - ) return results diff --git a/src/IntuneCD/backup/Intune/backup_appleEnrollmentProfile.py b/src/IntuneCD/backup/Intune/backup_appleEnrollmentProfile.py index 53e74be6..5b53258d 100644 --- a/src/IntuneCD/backup/Intune/backup_appleEnrollmentProfile.py +++ b/src/IntuneCD/backup/Intune/backup_appleEnrollmentProfile.py @@ -28,8 +28,12 @@ def savebackup(path, output, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Enrollment Profiles/Apple/" data = makeapirequest(ENDPOINT, token) + if audit: + graph_filter = "componentName eq 'Enrollment'" + audit_data = makeAuditRequest(graph_filter, token) if data["value"]: profile_ids = [] @@ -64,15 +68,10 @@ def savebackup(path, output, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data( - audit_data, path, f"{configpath}{fname}.{output}" - ) return results diff --git a/src/IntuneCD/backup/Intune/backup_applications.py b/src/IntuneCD/backup/Intune/backup_applications.py index 42a50b20..1e10e641 100644 --- a/src/IntuneCD/backup/Intune/backup_applications.py +++ b/src/IntuneCD/backup/Intune/backup_applications.py @@ -49,11 +49,14 @@ def savebackup(path, output, exclude, token, append_id, audit): """ results = {"config_count": 0, "outputs": []} - + audit_data = None data = makeapirequest(ENDPOINT, token, q_param) assignment_responses = batch_assignment( data, "deviceAppManagement/mobileApps/", "/assignments", token ) + if audit: + graph_filter = "componentName eq 'MobileApp'" + audit_data = makeAuditRequest(graph_filter, token) for app in data["value"]: app_name = "" @@ -65,6 +68,9 @@ def savebackup(path, output, exclude, token, append_id, audit): if assignments: app["assignments"] = assignments + # if audit: + # audit_data = get_audit_log(app["id"], audit_responses) + graph_id = app["id"] app = remove_keys(app) app.pop("description", None) @@ -138,13 +144,10 @@ def savebackup(path, output, exclude, token, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_assignmentFilters.py b/src/IntuneCD/backup/Intune/backup_assignmentFilters.py index edee0b9c..79b4f8ec 100644 --- a/src/IntuneCD/backup/Intune/backup_assignmentFilters.py +++ b/src/IntuneCD/backup/Intune/backup_assignmentFilters.py @@ -27,8 +27,12 @@ def savebackup(path, output, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Filters/" data = makeapirequest(ENDPOINT, token) + if audit: + graph_filter = "componentName eq 'AssignmentFilter'" + audit_data = makeAuditRequest(graph_filter, token) if data: for assign_filter in data["value"]: @@ -50,15 +54,10 @@ def savebackup(path, output, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data( - audit_data, path, f"{configpath}{fname}.{output}" - ) return results diff --git a/src/IntuneCD/backup/Intune/backup_compliance.py b/src/IntuneCD/backup/Intune/backup_compliance.py index c81ed93f..934f8546 100644 --- a/src/IntuneCD/backup/Intune/backup_compliance.py +++ b/src/IntuneCD/backup/Intune/backup_compliance.py @@ -29,6 +29,7 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Compliance Policies/Policies/" q_param = { "$expand": "scheduledActionsForRule($expand=scheduledActionConfigurations)" @@ -38,6 +39,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): assignment_responses = batch_assignment( data, "deviceManagement/deviceCompliancePolicies/", "/assignments", token ) + if audit: + graph_filter = "componentName eq 'DeviceCompliancePolicy'" + audit_data = makeAuditRequest(graph_filter, token) for policy in data["value"]: if prefix and not check_prefix_match(policy["displayName"], prefix): @@ -78,13 +82,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_compliancePartner.py b/src/IntuneCD/backup/Intune/backup_compliancePartner.py index dd50ade0..8c88ab47 100644 --- a/src/IntuneCD/backup/Intune/backup_compliancePartner.py +++ b/src/IntuneCD/backup/Intune/backup_compliancePartner.py @@ -28,8 +28,12 @@ def savebackup(path, output, exclude, token, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Partner Connections/Compliance/" data = makeapirequest(ENDPOINT, token) + if audit: + graph_filter = "componentName eq 'DeviceCompliancePolicy'" + audit_data = makeAuditRequest(graph_filter, token) for partner in data["value"]: if partner["partnerState"] == "unknown": @@ -57,13 +61,10 @@ def savebackup(path, output, exclude, token, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_configurationPolicies.py b/src/IntuneCD/backup/Intune/backup_configurationPolicies.py index 1bf570e8..07f69463 100644 --- a/src/IntuneCD/backup/Intune/backup_configurationPolicies.py +++ b/src/IntuneCD/backup/Intune/backup_configurationPolicies.py @@ -34,6 +34,7 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Settings Catalog/" policies = makeapirequest(BASE_ENDPOINT + "/configurationPolicies", token) policy_ids = [] @@ -49,6 +50,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): "/settings?&top=1000", token, ) + if audit: + graph_filter = "componentName eq 'DeviceConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) for policy in policies["value"]: if prefix and not check_prefix_match(policy["name"], prefix): @@ -84,13 +88,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_customAttributeShellScript.py b/src/IntuneCD/backup/Intune/backup_customAttributeShellScript.py index f4c17b4f..ce91f062 100644 --- a/src/IntuneCD/backup/Intune/backup_customAttributeShellScript.py +++ b/src/IntuneCD/backup/Intune/backup_customAttributeShellScript.py @@ -39,6 +39,7 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Custom Attributes/" data = makeapirequest(ENDPOINT, token) script_ids = [] @@ -54,6 +55,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): script_data_responses = batch_request( script_ids, "deviceManagement/deviceCustomAttributeShellScripts/", "", token ) + if audit: + graph_filter = "componentName eq 'DeviceConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) for script_data in script_data_responses: if prefix and not check_prefix_match(script_data["displayName"], prefix): @@ -90,13 +94,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): f = open(configpath + "Script Data/" + script_file_name, "w", encoding="utf-8") f.write(decoded) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_deviceCategories.py b/src/IntuneCD/backup/Intune/backup_deviceCategories.py index a56c2454..bd512e02 100644 --- a/src/IntuneCD/backup/Intune/backup_deviceCategories.py +++ b/src/IntuneCD/backup/Intune/backup_deviceCategories.py @@ -27,9 +27,12 @@ def savebackup(path, output, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} - + audit_data = None configpath = path + "/" + "Device Categories/" data = makeapirequest(ENDPOINT, token) + if audit: + graph_filter = "componentName eq 'Enrollment'" + audit_data = makeAuditRequest(graph_filter, token) if data["value"]: for item in data["value"]: @@ -50,15 +53,10 @@ def savebackup(path, output, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data( - audit_data, path, f"{configpath}{fname}.{output}" - ) return results diff --git a/src/IntuneCD/backup/Intune/backup_deviceManagementSettings.py b/src/IntuneCD/backup/Intune/backup_deviceManagementSettings.py index 70db0bb7..92aab711 100644 --- a/src/IntuneCD/backup/Intune/backup_deviceManagementSettings.py +++ b/src/IntuneCD/backup/Intune/backup_deviceManagementSettings.py @@ -26,9 +26,14 @@ def savebackup(path, output, audit, token): """ results = {"config_count": 0, "outputs": []} - + audit_data = None configpath = path + "/" + "Device Management Settings/" data = makeapirequest(ENDPOINT, token) + if audit: + graph_filter = ( + "resources/any(s:s/auditResourceType eq 'DeviceManagementSettings')" + ) + audit_data = makeAuditRequest(graph_filter, token) if data: results["config_count"] += 1 @@ -42,16 +47,13 @@ def savebackup(path, output, audit, token): results["outputs"].append(fname) - if audit: - graph_filter = ( - "resources/any(s:s/auditResourceType eq 'DeviceManagementSettings')" - ) - audit_data = makeAuditRequest( - "", - graph_filter, - token, + if audit_data: + compare_data = { + "type": "auditResourceType", + "value": "DeviceManagementSettings", + } + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_enrollmentConfigurations.py b/src/IntuneCD/backup/Intune/backup_enrollmentConfigurations.py index d385e9ff..6c08e8af 100644 --- a/src/IntuneCD/backup/Intune/backup_enrollmentConfigurations.py +++ b/src/IntuneCD/backup/Intune/backup_enrollmentConfigurations.py @@ -32,12 +32,16 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Enrollment Configurations/" data = makeapirequest(ENDPOINT, token) assignment_responses = batch_assignment( data, "deviceManagement/deviceEnrollmentConfigurations/", "/assignments", token ) + if audit: + graph_filter = "componentName eq 'Enrollment'" + audit_data = makeAuditRequest(graph_filter, token) for config in data["value"]: if prefix and not check_prefix_match(config["displayName"], prefix): @@ -78,13 +82,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_groupPolicyConfiguration.py b/src/IntuneCD/backup/Intune/backup_groupPolicyConfiguration.py index f2742393..4829b3bb 100644 --- a/src/IntuneCD/backup/Intune/backup_groupPolicyConfiguration.py +++ b/src/IntuneCD/backup/Intune/backup_groupPolicyConfiguration.py @@ -29,12 +29,16 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Group Policy Configurations/" data = makeapirequest(ENDPOINT, token) assignment_responses = batch_assignment( data, "deviceManagement/groupPolicyConfigurations/", "/assignments", token ) + if audit: + graph_filter = "componentName eq 'DeviceConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) for profile in data["value"]: if prefix and not check_prefix_match(profile["displayName"], prefix): @@ -77,13 +81,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_managedGPlay.py b/src/IntuneCD/backup/Intune/backup_managedGPlay.py index 4c27b34c..d442b5c7 100644 --- a/src/IntuneCD/backup/Intune/backup_managedGPlay.py +++ b/src/IntuneCD/backup/Intune/backup_managedGPlay.py @@ -26,8 +26,12 @@ def savebackup(path, output, exclude, token, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = f"{path}/Managed Google Play/" data = makeapirequest(ENDPOINT, token) + if audit: + graph_filter = "resources/any(s:s/auditResourceType eq 'Microsoft.Management.Services.Api.AndroidManagedStoreAccountEnterpriseSettings')" + audit_data = makeAuditRequest(graph_filter, token) if data: results["config_count"] += 1 @@ -48,14 +52,13 @@ def savebackup(path, output, exclude, token, append_id, audit): results["outputs"].append(fname) - if audit: - graph_filter = "resources/any(s:s/auditResourceType eq 'Microsoft.Management.Services.Api.AndroidManagedStoreAccountEnterpriseSettings')" - audit_data = makeAuditRequest( - "", - graph_filter, - token, + if audit_data: + compare_data = { + "type": "auditResourceType", + "value": "Microsoft.Management.Services.Api.AndroidManagedStoreAccountEnterpriseSettings", + } + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_managementIntents.py b/src/IntuneCD/backup/Intune/backup_managementIntents.py index 81b3fa17..28a4b895 100644 --- a/src/IntuneCD/backup/Intune/backup_managementIntents.py +++ b/src/IntuneCD/backup/Intune/backup_managementIntents.py @@ -33,6 +33,7 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Management Intents/" intents = makeapirequest(BASE_ENDPOINT + "/intents", token) templates = makeapirequest(TEMPLATE_ENDPOINT, token) @@ -41,6 +42,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): intents, "deviceManagement/intents/", "/assignments", token ) intent_responses = batch_intents(intents, token) + if audit: + graph_filter = "componentName eq 'DeviceIntent'" + audit_data = makeAuditRequest(graph_filter, token) if intent_responses: for intent_value in intent_responses["value"]: @@ -77,15 +81,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data( - audit_data, path, f"{configpath}{fname}.{output}" - ) return results diff --git a/src/IntuneCD/backup/Intune/backup_managementPartner.py b/src/IntuneCD/backup/Intune/backup_managementPartner.py index dc4a2915..ea2f4a4f 100644 --- a/src/IntuneCD/backup/Intune/backup_managementPartner.py +++ b/src/IntuneCD/backup/Intune/backup_managementPartner.py @@ -26,8 +26,12 @@ def savebackup(path, output, token, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Partner Connections/Management/" data = makeapirequest(ENDPOINT, token) + if audit: + graph_filter = "componentName eq 'Enrollment'" + audit_data = makeAuditRequest(graph_filter, token) for partner in data["value"]: if partner["isConfigured"] is False: @@ -49,13 +53,10 @@ def savebackup(path, output, token, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_notificationTemplate.py b/src/IntuneCD/backup/Intune/backup_notificationTemplate.py index 9cb81f2f..f18aa720 100644 --- a/src/IntuneCD/backup/Intune/backup_notificationTemplate.py +++ b/src/IntuneCD/backup/Intune/backup_notificationTemplate.py @@ -29,9 +29,13 @@ def savebackup(path, output, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Compliance Policies/Message Templates/" q_param = "?$expand=localizedNotificationMessages" data = makeapirequest(ENDPOINT, token, q_param) + if audit: + graph_filter = "componentName eq 'NotificationMessageTemplate'" + audit_data = makeAuditRequest(graph_filter, token) for template in data["value"]: if prefix and not check_prefix_match(template["displayName"], prefix): @@ -61,13 +65,10 @@ def savebackup(path, output, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_powershellScripts.py b/src/IntuneCD/backup/Intune/backup_powershellScripts.py index 37ad5f5d..9156c933 100644 --- a/src/IntuneCD/backup/Intune/backup_powershellScripts.py +++ b/src/IntuneCD/backup/Intune/backup_powershellScripts.py @@ -36,6 +36,7 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Scripts/Powershell/" data = makeapirequest(ENDPOINT, token) if data["value"]: @@ -49,6 +50,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): script_data_responses = batch_request( script_ids, "deviceManagement/deviceManagementScripts/", "", token ) + if audit: + graph_filter = "componentName eq 'DeviceConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) for script_data in script_data_responses: if prefix and not check_prefix_match(script_data["displayName"], prefix): @@ -80,16 +84,11 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data( - audit_data, path, f"{configpath}{fname}.{output}" - ) # Save Powershell script data to the script data folder if script_data.get("scriptContent"): diff --git a/src/IntuneCD/backup/Intune/backup_proactiveRemediation.py b/src/IntuneCD/backup/Intune/backup_proactiveRemediation.py index 2c0c0ff6..84dab2bd 100644 --- a/src/IntuneCD/backup/Intune/backup_proactiveRemediation.py +++ b/src/IntuneCD/backup/Intune/backup_proactiveRemediation.py @@ -36,8 +36,13 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = f"{path}/Proactive Remediations/" data = makeapirequest(ENDPOINT, token) + if audit: + graph_filter = "componentName eq 'DeviceConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) + if data["value"]: pr_ids = [] for script in data["value"]: @@ -79,16 +84,11 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data( - audit_data, path, f"{configpath}{fname}.{output}" - ) if not os.path.exists(f"{configpath}/Script Data"): os.makedirs(f"{configpath}/Script Data") diff --git a/src/IntuneCD/backup/Intune/backup_profiles.py b/src/IntuneCD/backup/Intune/backup_profiles.py index ce0c2469..ef8be911 100644 --- a/src/IntuneCD/backup/Intune/backup_profiles.py +++ b/src/IntuneCD/backup/Intune/backup_profiles.py @@ -34,12 +34,16 @@ def savebackup( """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Device Configurations/" data = makeapirequest(ENDPOINT, token) assignment_responses = batch_assignment( data, "deviceManagement/deviceConfigurations/", "/assignments", token ) + if audit: + graph_filter = "componentName eq 'DeviceConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) for profile in data["value"]: if prefix and not check_prefix_match(profile["displayName"], prefix): @@ -86,16 +90,11 @@ def savebackup( results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data( - audit_data, path, f"{configpath}{fname}.{output}" - ) # If Device Configuration is custom Win10 and the OMA settings are # encrypted, get them in plain text @@ -140,16 +139,11 @@ def savebackup( results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data( - audit_data, path, f"{configpath}{fname}.{output}" - ) # If Device Configuration are not custom, save it as JSON or YAML # depending on configured value in "-o" @@ -158,15 +152,10 @@ def savebackup( results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data( - audit_data, path, f"{configpath}{fname}.{output}" - ) return results diff --git a/src/IntuneCD/backup/Intune/backup_remoteAssistancePartner.py b/src/IntuneCD/backup/Intune/backup_remoteAssistancePartner.py index 1e8b3d4d..de2b80ad 100644 --- a/src/IntuneCD/backup/Intune/backup_remoteAssistancePartner.py +++ b/src/IntuneCD/backup/Intune/backup_remoteAssistancePartner.py @@ -26,8 +26,12 @@ def savebackup(path, output, token, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Partner Connections/Remote Assistance/" data = makeapirequest(ENDPOINT, token) + if audit: + graph_filter = "componentName eq 'ManagedDevices'" + audit_data = makeAuditRequest(graph_filter, token) for partner in data["value"]: if partner["onboardingStatus"] == "notOnboarded": @@ -49,13 +53,10 @@ def savebackup(path, output, token, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_roles.py b/src/IntuneCD/backup/Intune/backup_roles.py index ad8afc87..e1dd7cac 100644 --- a/src/IntuneCD/backup/Intune/backup_roles.py +++ b/src/IntuneCD/backup/Intune/backup_roles.py @@ -49,9 +49,13 @@ def _get_group_names(obj): return groups results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Roles/" q_param = {"$filter": "isBuiltIn eq false"} data = makeapirequest(ENDPOINT, token, q_param) + if audit: + graph_filter = "componentName eq 'RoleBasedAccessControl'" + audit_data = makeAuditRequest(graph_filter, token) for role in data["value"]: results["config_count"] += 1 @@ -107,13 +111,10 @@ def _get_group_names(obj): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_scopeTags.py b/src/IntuneCD/backup/Intune/backup_scopeTags.py index 28358ba1..6689065d 100644 --- a/src/IntuneCD/backup/Intune/backup_scopeTags.py +++ b/src/IntuneCD/backup/Intune/backup_scopeTags.py @@ -27,13 +27,16 @@ def savebackup(path, output, exclude, token, append_id, audit): """ results = {"config_count": 0, "outputs": []} - + audit_data = None configpath = path + "/" + "Scope Tags/" data = makeapirequest(ENDPOINT, token) assignment_responses = batch_assignment( data, "deviceManagement/roleScopeTags/", "/assignments", token ) + if audit: + graph_filter = "componentName eq 'RoleBasedAccessControl'" + audit_data = makeAuditRequest(graph_filter, token) for tag in data["value"]: results["config_count"] += 1 @@ -57,13 +60,10 @@ def savebackup(path, output, exclude, token, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - tag_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": tag_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_shellScripts.py b/src/IntuneCD/backup/Intune/backup_shellScripts.py index 52bd6d15..05edc249 100644 --- a/src/IntuneCD/backup/Intune/backup_shellScripts.py +++ b/src/IntuneCD/backup/Intune/backup_shellScripts.py @@ -39,6 +39,7 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Scripts/Shell/" data = makeapirequest(ENDPOINT, token) script_ids = [] @@ -51,6 +52,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): script_data_responses = batch_request( script_ids, "deviceManagement/deviceShellScripts/", "", token ) + if audit: + graph_filter = "componentName eq 'DeviceConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) for script_data in script_data_responses: if prefix and not check_prefix_match(script_data["displayName"], prefix): @@ -80,14 +84,11 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") # Save Shell script data to the script data folder if not os.path.exists(configpath + "Script Data/"): diff --git a/src/IntuneCD/backup/Intune/backup_vppTokens.py b/src/IntuneCD/backup/Intune/backup_vppTokens.py index 93ac662e..091e3321 100644 --- a/src/IntuneCD/backup/Intune/backup_vppTokens.py +++ b/src/IntuneCD/backup/Intune/backup_vppTokens.py @@ -26,8 +26,12 @@ def savebackup(path, output, token, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = f"{path}/Apple VPP Tokens/" data = makeapirequest(ENDPOINT, token) + if audit: + graph_filter = "componentName eq 'MobileApp'" + audit_data = makeAuditRequest(graph_filter, token) for vpp_token in data["value"]: results["config_count"] += 1 @@ -47,13 +51,10 @@ def savebackup(path, output, token, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_windowsDriverUpdates.py b/src/IntuneCD/backup/Intune/backup_windowsDriverUpdates.py index d8639d6d..aac0ba1c 100644 --- a/src/IntuneCD/backup/Intune/backup_windowsDriverUpdates.py +++ b/src/IntuneCD/backup/Intune/backup_windowsDriverUpdates.py @@ -31,6 +31,7 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Driver Updates/" data = makeapirequest(ENDPOINT, token) @@ -40,6 +41,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): "/assignments", token, ) + if audit: + graph_filter = "componentName eq 'SoftwareUpdateConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) for profile in data["value"]: if prefix and not check_prefix_match(profile["displayName"], prefix): @@ -66,13 +70,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_windowsEnrollmentProfile.py b/src/IntuneCD/backup/Intune/backup_windowsEnrollmentProfile.py index d989ce55..19210b29 100644 --- a/src/IntuneCD/backup/Intune/backup_windowsEnrollmentProfile.py +++ b/src/IntuneCD/backup/Intune/backup_windowsEnrollmentProfile.py @@ -29,6 +29,7 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Enrollment Profiles/Windows/" data = makeapirequest(ENDPOINT, token) @@ -38,6 +39,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): "/assignments", token, ) + if audit: + graph_filter = "componentName eq 'Enrollment'" + audit_data = makeAuditRequest(graph_filter, token) for profile in data["value"]: if prefix and not check_prefix_match(profile["displayName"], prefix): @@ -64,13 +68,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_windowsFeatureUpdates.py b/src/IntuneCD/backup/Intune/backup_windowsFeatureUpdates.py index 3be37095..4678623e 100644 --- a/src/IntuneCD/backup/Intune/backup_windowsFeatureUpdates.py +++ b/src/IntuneCD/backup/Intune/backup_windowsFeatureUpdates.py @@ -31,6 +31,7 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Feature Updates/" data = makeapirequest(ENDPOINT, token) @@ -40,6 +41,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): "/assignments", token, ) + if audit: + graph_filter = "componentName eq 'SoftwareUpdateConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) for profile in data["value"]: if prefix and not check_prefix_match(profile["displayName"], prefix): @@ -66,13 +70,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/backup/Intune/backup_windowsQualityUpdates.py b/src/IntuneCD/backup/Intune/backup_windowsQualityUpdates.py index 15eebb66..19aba458 100644 --- a/src/IntuneCD/backup/Intune/backup_windowsQualityUpdates.py +++ b/src/IntuneCD/backup/Intune/backup_windowsQualityUpdates.py @@ -31,6 +31,7 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): """ results = {"config_count": 0, "outputs": []} + audit_data = None configpath = path + "/" + "Quality Updates/" data = makeapirequest(ENDPOINT, token) @@ -40,6 +41,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): "/assignments", token, ) + if audit: + graph_filter = "componentName eq 'SoftwareUpdateConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) for profile in data["value"]: if prefix and not check_prefix_match(profile["displayName"], prefix): @@ -66,13 +70,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["outputs"].append(fname) - if audit: - audit_data = makeAuditRequest( - graph_id, - "", - token, + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" ) - if audit_data: - process_audit_data(audit_data, path, f"{configpath}{fname}.{output}") return results diff --git a/src/IntuneCD/intunecdlib/graph_request.py b/src/IntuneCD/intunecdlib/graph_request.py index 30c16306..ce3e7ebc 100644 --- a/src/IntuneCD/intunecdlib/graph_request.py +++ b/src/IntuneCD/intunecdlib/graph_request.py @@ -238,7 +238,7 @@ def makeapirequestPut(patchEndpoint, token, q_param=None, jdata=None, status_cod ) -def makeAuditRequest(pid, graph_filter, token): +def makeAuditRequest(graph_filter, token): """ This function makes a GET request to the Microsoft Graph API to get the audit logs for a specific object. @@ -247,16 +247,21 @@ def makeAuditRequest(pid, graph_filter, token): :param token: The token to use for authenticating the request. """ - # Get the current date and time and set time to 00:00:00 - start_date = datetime.datetime.now().strftime("%Y-%m-%dT00:00:00.000Z") + audit_data = [] + # Get the date and time 24 hours ago and format it + start_date = datetime.datetime.now() - datetime.timedelta(days=1) + start_date = start_date.strftime("%Y-%m-%dT%H:%M:%S.%fZ") # Get the current date and time end_date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ") # Create query to get audit logs for the object - if not graph_filter: - graph_filter = f"resources/any(s:s/resourceId eq '{pid}')" + # if not graph_filter: + # graph_filter = f"resources/any(s:s/resourceId eq '{pid}')" q_param = { - "$filter": f"{graph_filter} and activityDateTime gt {start_date} and activityDateTime le {end_date} and activityOperationType ne 'Get'", - "$select": "actor,activityDateTime,activityOperationType,activityResult", + "$filter": ( + f"{graph_filter} and activityDateTime gt {start_date} and activityDateTime le {end_date} and " + "activityOperationType ne 'Get'" + ), + "$select": "actor,activityDateTime,activityOperationType,activityResult,resources", "$orderby": "activityDateTime desc", } @@ -266,14 +271,21 @@ def makeAuditRequest(pid, graph_filter, token): # If there are audit logs, return the latest one if data["value"]: - # is the actor an app or a user? - if data["value"][0]["actor"]["auditActorType"] == "ItPro": - actor = data["value"][0]["actor"].get("userPrincipalName") - else: - actor = data["value"][0]["actor"].get("applicationDisplayName") - return { - "actor": actor, - "activityDateTime": data["value"][0]["activityDateTime"], - "activityOperationType": data["value"][0]["activityOperationType"], - "activityResult": data["value"][0]["activityResult"], - } + for audit_log in data["value"]: + # is the actor an app or a user? + if audit_log["actor"]["auditActorType"] == "ItPro": + actor = audit_log["actor"].get("userPrincipalName") + else: + actor = audit_log["actor"].get("applicationDisplayName") + audit_data.append( + { + "resourceId": audit_log["resources"][0]["resourceId"], + "auditResourceType": audit_log["resources"][0]["auditResourceType"], + "actor": actor, + "activityDateTime": audit_log["activityDateTime"], + "activityOperationType": audit_log["activityOperationType"], + "activityResult": audit_log["activityResult"], + } + ) + + return audit_data diff --git a/src/IntuneCD/intunecdlib/process_audit_data.py b/src/IntuneCD/intunecdlib/process_audit_data.py index 89dfc0c6..bcdab1b2 100644 --- a/src/IntuneCD/intunecdlib/process_audit_data.py +++ b/src/IntuneCD/intunecdlib/process_audit_data.py @@ -11,6 +11,9 @@ def _git_installed(): + """ + Checks if git is installed. + """ cmd = ["git", "--version"] log("_git_installed", "Running command git --version to check if git is installed.") git_version = subprocess.run(cmd, capture_output=True, text=True, check=False) @@ -22,7 +25,13 @@ def _git_installed(): return True -def _configure_git(audit_data, path): +def _configure_git(audit_record, path): + """ + Configures git with the user email and name. + + :param audit_record: The audit record to use for the configuration. + :param path: The path to the git repo. + """ cmd = [ "git", "-C", @@ -30,11 +39,11 @@ def _configure_git(audit_data, path): "config", "--local", "user.email", - f"{audit_data['actor']}", + f"{audit_record['actor']}", ] log( "_configure_git", - f"Running command {cmd} to configure git user email to {audit_data['actor']}.", + f"Running command {cmd} to configure git user email to {audit_record['actor']}.", ) subprocess.run( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False @@ -48,7 +57,7 @@ def _configure_git(audit_data, path): "config", "--local", "user.name", - f"{audit_data['actor']}", + f"{audit_record['actor']}", ] log("_configure_git", f"Running command {cmd} to configure git user name.") subprocess.run( @@ -57,6 +66,12 @@ def _configure_git(audit_data, path): def _check_if_git_repo(path, file): + """ + Checks if the path is a git repo. + + :param path: The path to check. + :param file: The file to check. + """ cmd = ["git", "-C", path, "rev-parse", "--is-inside-work-tree"] log("_check_if_git_repo", f"Path is set to {path} and file is set to {file}.") log( @@ -74,6 +89,12 @@ def _check_if_git_repo(path, file): def _git_check_modified(path, file): + """ + Checks if the file has been modified. + + :param path: The path to the git repo. + :param file: The file to check. + """ cmd = ["git", "-C", path, "diff", "--name-only", f"{file}"] log( "_git_check_modified", @@ -84,6 +105,12 @@ def _git_check_modified(path, file): def _git_check_new_file(path, file): + """ + Checks if the file is a new file. + + :param path: The path to the git repo. + :param file: The file to check. + """ # check if it is a new file cmd = ["git", "-C", path, "ls-files", "--error-unmatch", f"{file}"] log( @@ -98,7 +125,14 @@ def _git_check_new_file(path, file): return False -def _git_commit_changes(audit_data, path, file): +def _git_commit_changes(audit_record, path, file): + """ + Commits the changes to the git repo. + + :param audit_record: The audit record to use for the commit. + :param path: The path to the git repo. + :param file: The file to commit. + """ # commit the changes cmd = ["git", "-C", path, "add", f"{file}"] log("_git_commit_changes", f"Running command {cmd} to add {file} to the git repo.") @@ -113,8 +147,8 @@ def _git_commit_changes(audit_data, path, file): "commit", "-m", ( - f"Updated by {audit_data['actor']} on {audit_data['activityDateTime']}, " - f"change type: {audit_data['activityOperationType']}, result: {audit_data['activityResult']}" + f"Updated by {audit_record['actor']} on {audit_record['activityDateTime']}, " + f"change type: {audit_record['activityOperationType']}, result: {audit_record['activityResult']}" ), ] @@ -128,12 +162,35 @@ def _git_commit_changes(audit_data, path, file): log("_git_commit_changes", f"Commit was not successful, error: {commit.stderr}") -def process_audit_data(audit_data, path, file): +def _get_payload_from_audit_data(audit_data, compare_data): + """ + Gets the payload from the audit data. + + :param audit_data: The audit data to get the payload from. + :param pid: The resource ID to get the payload for. + """ + + records = [] + for record in audit_data: + if record[compare_data["type"]] == compare_data["value"]: + records.append(record) + + if records: + # sort the records by activityDateTime + records.sort(key=lambda x: x["activityDateTime"], reverse=True) + records = records[0] + + return records + + +def process_audit_data(audit_data, compare_data, path, file): """ Processes the audit data from Intune. :param audit_data: The audit data to process. - :return: The processed audit data. + :param pid: The resource ID to process. + :param path: The path to the git repo. + :param file: The file to process. """ log("process_audit_data", f"Processing audit data for {file} in path {path}.") @@ -142,11 +199,15 @@ def process_audit_data(audit_data, path, file): # Commit the changes if git_repo: + record = _get_payload_from_audit_data(audit_data, compare_data) + if not record: + log("process_audit_data", f"No audit data found for {file}.") + return False # check if git is installed if not _git_installed(): return # configure git - _configure_git(audit_data, path) + _configure_git(record, path) # check if file has been modified result = _git_check_modified(path, file) @@ -155,7 +216,7 @@ def process_audit_data(audit_data, path, file): if result or file_not_found: # commit the changes - _git_commit_changes(audit_data, path, file) + _git_commit_changes(record, path, file) else: log( "process_audit_data", From e35ebd3a5037941b87a62035cbd80428bbabf8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:29:37 +0100 Subject: [PATCH 06/35] bump to 2.2.0.beta3 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 252f81f1..bf2dae75 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = IntuneCD -version = 2.2.0.beta2 +version = 2.2.0.beta3 author = Tobias Almén author_email = almenscorner@outlook.com description = Tool to backup and update configurations in Intune From 50c207f3a229ea157018042c26a3df10c577abdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:00:19 +0100 Subject: [PATCH 07/35] add processing of scope tags --- .../backup/Intune/backup_AppProtection.py | 6 +- .../backup/Intune/backup_appConfiguration.py | 6 +- .../backup/Intune/backup_applications.py | 6 +- .../backup/Intune/backup_assignmentFilters.py | 6 +- .../backup/Intune/backup_compliance.py | 6 +- .../Intune/backup_configurationPolicies.py | 6 +- .../backup_customAttributeShellScript.py | 7 +- .../backup/Intune/backup_deviceCategories.py | 5 +- .../Intune/backup_enrollmentConfigurations.py | 6 +- .../Intune/backup_enrollmentStatusPage.py | 6 +- .../Intune/backup_groupPolicyConfiguration.py | 6 +- .../backup/Intune/backup_managementIntents.py | 6 +- .../Intune/backup_notificationTemplate.py | 7 +- .../backup/Intune/backup_powershellScripts.py | 6 +- .../Intune/backup_proactiveRemediation.py | 6 +- src/IntuneCD/backup/Intune/backup_profiles.py | 14 +- src/IntuneCD/backup/Intune/backup_roles.py | 5 +- .../backup/Intune/backup_shellScripts.py | 6 +- .../backup/Intune/backup_vppTokens.py | 6 +- .../Intune/backup_windowsDriverUpdates.py | 6 +- .../Intune/backup_windowsEnrollmentProfile.py | 6 +- .../Intune/backup_windowsFeatureUpdates.py | 6 +- .../Intune/backup_windowsQualityUpdates.py | 6 +- src/IntuneCD/backup_intune.py | 98 +++++++++--- .../intunecdlib/process_scope_tags.py | 64 ++++++++ .../update/Intune/update_appConfiguration.py | 12 +- .../update/Intune/update_appProtection.py | 12 +- .../update/Intune/update_assignmentFilter.py | 6 +- .../update/Intune/update_compliance.py | 11 +- .../Intune/update_configurationPolicies.py | 11 +- .../update_customAttributeShellScript.py | 11 +- .../update/Intune/update_deviceCategories.py | 6 +- .../Intune/update_enrollmentConfigurations.py | 12 +- .../Intune/update_enrollmentStatusPage.py | 11 +- .../Intune/update_groupPolicyConfiguration.py | 11 +- .../update/Intune/update_managementIntents.py | 11 +- .../Intune/update_notificationTemplate.py | 7 +- .../update/Intune/update_powershellScripts.py | 11 +- .../Intune/update_proactiveRemediation.py | 11 +- src/IntuneCD/update/Intune/update_profiles.py | 11 +- src/IntuneCD/update/Intune/update_roles.py | 5 +- .../update/Intune/update_scopeTags.py | 2 +- .../update/Intune/update_shellScripts.py | 13 +- .../Intune/update_windowsDriverUpdates.py | 11 +- .../Intune/update_windowsEnrollmentProfile.py | 11 +- .../Intune/update_windowsFeatureUpdates.py | 11 +- .../Intune/update_windowsQualityUpdates.py | 11 +- src/IntuneCD/update_intune.py | 45 +++--- .../Intune/test_backup_appProtection.py | 48 +++++- .../Backup/Intune/test_backup_applications.py | 139 ++++++++++++++++-- .../Intune/test_backup_assignmentFilter.py | 46 +++++- tests/Backup/Intune/test_backup_compliance.py | 46 +++++- .../test_backup_configurationPolicies.py | 45 +++++- .../test_backup_customAttributeShellScript.py | 45 +++++- .../Intune/test_backup_deviceCategories.py | 50 ++++++- .../test_backup_enrollmentConfigurations.py | 47 +++++- .../test_backup_enrollmentStatusPage.py | 47 +++++- .../test_backup_groupPolicyConfiguration.py | 46 +++++- .../Intune/test_backup_managementIntents.py | 46 +++++- .../test_backup_notificationTemplate.py | 49 +++++- .../Intune/test_backup_powershellScripts.py | 50 ++++++- .../test_backup_proactiveRemediation.py | 52 ++++++- tests/Backup/Intune/test_backup_profiles.py | 102 +++++++++++++ tests/Backup/Intune/test_backup_roles.py | 43 +++++- .../Backup/Intune/test_backup_shellScripts.py | 46 +++++- tests/Backup/Intune/test_backup_vppTokens.py | 46 +++++- .../test_backup_windowsDriverUpdates.py | 44 +++++- .../test_backup_windowsEnrollmentProfile.py | 46 +++++- .../test_backup_windowsFeatureUpdates.py | 44 +++++- .../test_backup_windowsQualityUpdates.py | 44 +++++- .../Intune/test_update_ManagementIntents.py | 15 ++ tests/Update/Intune/test_update_compliance.py | 15 ++ .../test_update_customAttributeShellScript.py | 19 +++ .../Intune/test_update_deviceCategories.py | 34 ++++- .../test_update_enrollmentStatusPage.py | 15 ++ .../test_update_notificationTemplate.py | 42 ++++-- .../Intune/test_update_powershellScripts.py | 20 +++ .../test_update_proactiveRemediation.py | 21 +++ tests/Update/Intune/test_update_profiles.py | 15 ++ tests/Update/Intune/test_update_roles.py | 15 +- .../Update/Intune/test_update_shellScripts.py | 18 +++ .../test_update_windowsDriverUpdates.py | 15 ++ .../test_update_windowsEnrollmentProfile.py | 15 ++ .../test_update_windowsFeatureUpdates.py | 15 ++ .../test_update_windowsQualityUpdates.py | 15 ++ 85 files changed, 1870 insertions(+), 161 deletions(-) create mode 100644 src/IntuneCD/intunecdlib/process_scope_tags.py diff --git a/src/IntuneCD/backup/Intune/backup_AppProtection.py b/src/IntuneCD/backup/Intune/backup_AppProtection.py index 204e0e57..29b1ab31 100644 --- a/src/IntuneCD/backup/Intune/backup_AppProtection.py +++ b/src/IntuneCD/backup/Intune/backup_AppProtection.py @@ -10,6 +10,7 @@ from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -18,7 +19,7 @@ # Get all App Protection policies and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all App Protection policies in Intune to a JSON or YAML file. @@ -50,6 +51,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["config_count"] += 1 + if scope_tags: + profile = get_scope_tags_name(profile, scope_tags) + if ( "assignments" not in exclude and profile["@odata.type"] != "#microsoft.graph.defaultManagedAppProtection" diff --git a/src/IntuneCD/backup/Intune/backup_appConfiguration.py b/src/IntuneCD/backup/Intune/backup_appConfiguration.py index 4064a811..0449a760 100644 --- a/src/IntuneCD/backup/Intune/backup_appConfiguration.py +++ b/src/IntuneCD/backup/Intune/backup_appConfiguration.py @@ -13,6 +13,7 @@ from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -24,7 +25,7 @@ # Get all App Configuration policies and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all App Configuration policies in Intune to a JSON or YAML file. @@ -52,6 +53,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): continue results["config_count"] += 1 + + if scope_tags: + profile = get_scope_tags_name(profile, scope_tags) if "assignments" not in exclude: assignments = get_object_assignment(profile["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_applications.py b/src/IntuneCD/backup/Intune/backup_applications.py index 1e10e641..aa6c497d 100644 --- a/src/IntuneCD/backup/Intune/backup_applications.py +++ b/src/IntuneCD/backup/Intune/backup_applications.py @@ -11,6 +11,7 @@ from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -38,7 +39,7 @@ def match(platform, odata_input) -> bool: # Get all applications and save them in specified path -def savebackup(path, output, exclude, token, append_id, audit): +def savebackup(path, output, exclude, token, append_id, audit, scope_tags): """ Saves all applications in Intune to a JSON or YAML file. @@ -63,6 +64,9 @@ def savebackup(path, output, exclude, token, append_id, audit): platform = "" results["config_count"] += 1 + if scope_tags: + app = get_scope_tags_name(app, scope_tags) + if "assignments" not in exclude: assignments = get_object_assignment(app["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_assignmentFilters.py b/src/IntuneCD/backup/Intune/backup_assignmentFilters.py index 79b4f8ec..e92cb6c0 100644 --- a/src/IntuneCD/backup/Intune/backup_assignmentFilters.py +++ b/src/IntuneCD/backup/Intune/backup_assignmentFilters.py @@ -9,6 +9,7 @@ from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -17,7 +18,7 @@ # Get all Filters and save them in specified path -def savebackup(path, output, token, prefix, append_id, audit): +def savebackup(path, output, token, prefix, append_id, audit, scope_tags): """ Saves all Filter in Intune to a JSON or YAML file. @@ -39,6 +40,9 @@ def savebackup(path, output, token, prefix, append_id, audit): if prefix and not check_prefix_match(assign_filter["displayName"], prefix): continue + if scope_tags: + assign_filter = get_scope_tags_name(assign_filter, scope_tags) + results["config_count"] += 1 graph_id = assign_filter["id"] assign_filter = remove_keys(assign_filter) diff --git a/src/IntuneCD/backup/Intune/backup_compliance.py b/src/IntuneCD/backup/Intune/backup_compliance.py index 934f8546..5673b8c8 100644 --- a/src/IntuneCD/backup/Intune/backup_compliance.py +++ b/src/IntuneCD/backup/Intune/backup_compliance.py @@ -10,6 +10,7 @@ from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -18,7 +19,7 @@ # Get all Compliance policies and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Compliance policies in Intune to a JSON or YAML file. @@ -50,6 +51,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): results["config_count"] += 1 print("Backing up compliance policy: " + policy["displayName"]) + if scope_tags: + policy = get_scope_tags_name(policy, scope_tags) + if "assignments" not in exclude: assignments = get_object_assignment(policy["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_configurationPolicies.py b/src/IntuneCD/backup/Intune/backup_configurationPolicies.py index 07f69463..c23df638 100644 --- a/src/IntuneCD/backup/Intune/backup_configurationPolicies.py +++ b/src/IntuneCD/backup/Intune/backup_configurationPolicies.py @@ -15,6 +15,7 @@ ) from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -23,7 +24,7 @@ # Get all Configuration Policies and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Configuration Policies in Intune to a JSON or YAML file. @@ -67,6 +68,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): if settings: policy["settings"] = settings + if scope_tags: + policy = get_scope_tags_name(policy, scope_tags) + if "assignments" not in exclude: assignments = get_object_assignment(policy["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_customAttributeShellScript.py b/src/IntuneCD/backup/Intune/backup_customAttributeShellScript.py index ce91f062..6c0af163 100644 --- a/src/IntuneCD/backup/Intune/backup_customAttributeShellScript.py +++ b/src/IntuneCD/backup/Intune/backup_customAttributeShellScript.py @@ -17,6 +17,7 @@ ) from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -28,7 +29,7 @@ # Get all Custom Attribute Shell scripts and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Custom Attribute Shell scripts in Intune to a JSON or YAML file and script files. @@ -64,6 +65,10 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): continue results["config_count"] += 1 + + if scope_tags: + script_data = get_scope_tags_name(script_data, scope_tags) + if "assignments" not in exclude: assignments = get_object_assignment(script_data["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_deviceCategories.py b/src/IntuneCD/backup/Intune/backup_deviceCategories.py index bd512e02..3d402528 100644 --- a/src/IntuneCD/backup/Intune/backup_deviceCategories.py +++ b/src/IntuneCD/backup/Intune/backup_deviceCategories.py @@ -9,6 +9,7 @@ from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -17,7 +18,7 @@ # Get Device Categories information and save in specified path -def savebackup(path, output, token, prefix, append_id, audit): +def savebackup(path, output, token, prefix, append_id, audit, scope_tags): """ Save Device Categories to a JSON or YAML file. @@ -40,6 +41,8 @@ def savebackup(path, output, token, prefix, append_id, audit): continue results["config_count"] += 1 + if scope_tags: + item = get_scope_tags_name(item, scope_tags) graph_id = item["id"] item = remove_keys(item) print("Backing up Device Category: " + item["displayName"]) diff --git a/src/IntuneCD/backup/Intune/backup_enrollmentConfigurations.py b/src/IntuneCD/backup/Intune/backup_enrollmentConfigurations.py index 6c08e8af..99bce9c7 100644 --- a/src/IntuneCD/backup/Intune/backup_enrollmentConfigurations.py +++ b/src/IntuneCD/backup/Intune/backup_enrollmentConfigurations.py @@ -12,6 +12,7 @@ from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -22,7 +23,7 @@ # Get all Enrollment Configurations and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Enrollment Configurations in Intune to a JSON or YAML file. @@ -60,6 +61,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): print(f"Backing up Enrollment Config {config_type}: " + config["displayName"]) + if scope_tags: + config = get_scope_tags_name(config, scope_tags) + if "assignments" not in exclude: assignments = get_object_assignment(config["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_enrollmentStatusPage.py b/src/IntuneCD/backup/Intune/backup_enrollmentStatusPage.py index c58c986f..15e01349 100644 --- a/src/IntuneCD/backup/Intune/backup_enrollmentStatusPage.py +++ b/src/IntuneCD/backup/Intune/backup_enrollmentStatusPage.py @@ -9,6 +9,7 @@ from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment from ...intunecdlib.graph_request import makeapirequest +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -20,7 +21,7 @@ # Get all Windows Enrollment Status Page profiles and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id): +def savebackup(path, output, exclude, token, prefix, append_id, scope_tags): """ Saves all Windows Enrollment Status Page profiles in Intune to a JSON or YAML file. @@ -47,6 +48,9 @@ def savebackup(path, output, exclude, token, prefix, append_id): == "#microsoft.graph.windows10EnrollmentCompletionPageConfiguration" ): results["config_count"] += 1 + + if scope_tags: + profile = get_scope_tags_name(profile, scope_tags) if "assignments" not in exclude: assignments = get_object_assignment(profile["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_groupPolicyConfiguration.py b/src/IntuneCD/backup/Intune/backup_groupPolicyConfiguration.py index 4829b3bb..0639a509 100644 --- a/src/IntuneCD/backup/Intune/backup_groupPolicyConfiguration.py +++ b/src/IntuneCD/backup/Intune/backup_groupPolicyConfiguration.py @@ -10,6 +10,7 @@ from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -18,7 +19,7 @@ # Get all Group Policy Configurations and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Group Policy Configurations in Intune to a JSON or YAML file. @@ -62,6 +63,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): presentation = makeapirequest(presentation_endpoint, token) definition["presentationValues"] = presentation["value"] + if scope_tags: + profile = get_scope_tags_name(profile, scope_tags) + if "assignments" not in exclude: assignments = get_object_assignment(profile["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_managementIntents.py b/src/IntuneCD/backup/Intune/backup_managementIntents.py index 28a4b895..28c52b60 100644 --- a/src/IntuneCD/backup/Intune/backup_managementIntents.py +++ b/src/IntuneCD/backup/Intune/backup_managementIntents.py @@ -14,6 +14,7 @@ ) from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.save_output import save_output # Set MS Graph base endpoint @@ -22,7 +23,7 @@ # Get all Intents and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Intents in Intune to a JSON or YAML file. @@ -60,6 +61,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): configpath = path + "/" + "Management Intents/" + template_type + "/" + if scope_tags: + intent_value = get_scope_tags_name(intent_value, scope_tags) + if "assignments" not in exclude: assignments = get_object_assignment( intent_value["id"], assignment_responses diff --git a/src/IntuneCD/backup/Intune/backup_notificationTemplate.py b/src/IntuneCD/backup/Intune/backup_notificationTemplate.py index f18aa720..e1fb7970 100644 --- a/src/IntuneCD/backup/Intune/backup_notificationTemplate.py +++ b/src/IntuneCD/backup/Intune/backup_notificationTemplate.py @@ -9,6 +9,7 @@ from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -19,7 +20,7 @@ # Get all Notification Templates and save them in specified path -def savebackup(path, output, token, prefix, append_id, audit): +def savebackup(path, output, token, prefix, append_id, audit, scope_tags): """ Saves all Notification Templates in Intune to a JSON or YAML file. @@ -30,6 +31,7 @@ def savebackup(path, output, token, prefix, append_id, audit): results = {"config_count": 0, "outputs": []} audit_data = None + scope_tags = None configpath = path + "/" + "Compliance Policies/Message Templates/" q_param = "?$expand=localizedNotificationMessages" data = makeapirequest(ENDPOINT, token, q_param) @@ -52,6 +54,9 @@ def savebackup(path, output, token, prefix, append_id, audit): graph_id = template_data["id"] template_data = remove_keys(template_data) + if scope_tags: + template_data = get_scope_tags_name(template_data, scope_tags) + for locale in template_data["localizedNotificationMessages"]: remove_keys(locale) diff --git a/src/IntuneCD/backup/Intune/backup_powershellScripts.py b/src/IntuneCD/backup/Intune/backup_powershellScripts.py index 9156c933..7904c9ab 100644 --- a/src/IntuneCD/backup/Intune/backup_powershellScripts.py +++ b/src/IntuneCD/backup/Intune/backup_powershellScripts.py @@ -17,6 +17,7 @@ ) from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -25,7 +26,7 @@ # Get all Powershell scripts and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Powershell scripts in Intune to a JSON or YAML file and script files. @@ -59,6 +60,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): continue results["config_count"] += 1 + + if scope_tags: + script_data = get_scope_tags_name(script_data, scope_tags) if "assignments" not in exclude: assignments = get_object_assignment( script_data["id"], assignment_responses diff --git a/src/IntuneCD/backup/Intune/backup_proactiveRemediation.py b/src/IntuneCD/backup/Intune/backup_proactiveRemediation.py index 84dab2bd..2771df33 100644 --- a/src/IntuneCD/backup/Intune/backup_proactiveRemediation.py +++ b/src/IntuneCD/backup/Intune/backup_proactiveRemediation.py @@ -17,6 +17,7 @@ ) from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -25,7 +26,7 @@ # Get all Proactive Remediation and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Proactive Remediation in Intune to a JSON or YAML file and script files. @@ -61,6 +62,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): if "Microsoft" not in pr_details["publisher"]: results["config_count"] += 1 + + if scope_tags: + pr_details = get_scope_tags_name(pr_details, scope_tags) if "assignments" not in exclude: assignments = get_object_assignment( pr_details["id"], assignment_responses diff --git a/src/IntuneCD/backup/Intune/backup_profiles.py b/src/IntuneCD/backup/Intune/backup_profiles.py index ef8be911..658292f8 100644 --- a/src/IntuneCD/backup/Intune/backup_profiles.py +++ b/src/IntuneCD/backup/Intune/backup_profiles.py @@ -13,6 +13,7 @@ from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -22,7 +23,15 @@ # Get all Device Configurations and save them in specified path def savebackup( - path, output, exclude, token, prefix, append_id, ignore_omasettings, audit + path, + output, + exclude, + token, + prefix, + append_id, + ignore_omasettings, + audit, + scope_tags, ): """ Saves all Device Configurations in Intune to a JSON or YAML file and custom macOS/iOS to .mobileconfig. @@ -50,6 +59,9 @@ def savebackup( continue results["config_count"] += 1 + + if scope_tags: + profile = get_scope_tags_name(profile, scope_tags) if "assignments" not in exclude: assignments = get_object_assignment(profile["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_roles.py b/src/IntuneCD/backup/Intune/backup_roles.py index e1dd7cac..0d782035 100644 --- a/src/IntuneCD/backup/Intune/backup_roles.py +++ b/src/IntuneCD/backup/Intune/backup_roles.py @@ -8,6 +8,7 @@ from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -16,7 +17,7 @@ # Get all Roles and save them in specified path -def savebackup(path, output, exclude, token, append_id, audit): +def savebackup(path, output, exclude, token, append_id, audit, scope_tags): """ Saves all Roles in Intune to a JSON or YAML file. @@ -61,6 +62,8 @@ def _get_group_names(obj): results["config_count"] += 1 print("Backing up Role: " + role["displayName"]) + if scope_tags: + role = get_scope_tags_name(role, scope_tags) if "assignments" not in exclude: assignments = makeapirequest( ENDPOINT + f"/{role['id']}/roleAssignments", token diff --git a/src/IntuneCD/backup/Intune/backup_shellScripts.py b/src/IntuneCD/backup/Intune/backup_shellScripts.py index 05edc249..b8303638 100644 --- a/src/IntuneCD/backup/Intune/backup_shellScripts.py +++ b/src/IntuneCD/backup/Intune/backup_shellScripts.py @@ -17,6 +17,7 @@ ) from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -28,7 +29,7 @@ # Get all Shell scripts and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Shell scripts in Intune to a JSON or YAML file and script files. @@ -61,6 +62,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): continue results["config_count"] += 1 + + if scope_tags: + script_data = get_scope_tags_name(script_data, scope_tags) if "assignments" not in exclude: assignments = get_object_assignment(script_data["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_vppTokens.py b/src/IntuneCD/backup/Intune/backup_vppTokens.py index 091e3321..55416746 100644 --- a/src/IntuneCD/backup/Intune/backup_vppTokens.py +++ b/src/IntuneCD/backup/Intune/backup_vppTokens.py @@ -8,6 +8,7 @@ from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -16,7 +17,7 @@ # Get all VPP tokens and save them in specified path -def savebackup(path, output, token, append_id, audit): +def savebackup(path, output, token, append_id, audit, scope_tags): """ Save all VPP tokens in Intune to a JSON or YAML file. @@ -41,6 +42,9 @@ def savebackup(path, output, token, append_id, audit): print(f"Backing up VPP token: {token_name}") + if scope_tags: + vpp_token = get_scope_tags_name(vpp_token, scope_tags) + # Get filename without illegal characters fname = clean_filename(token_name) if append_id: diff --git a/src/IntuneCD/backup/Intune/backup_windowsDriverUpdates.py b/src/IntuneCD/backup/Intune/backup_windowsDriverUpdates.py index aac0ba1c..15c7f744 100644 --- a/src/IntuneCD/backup/Intune/backup_windowsDriverUpdates.py +++ b/src/IntuneCD/backup/Intune/backup_windowsDriverUpdates.py @@ -10,6 +10,7 @@ from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -20,7 +21,7 @@ # Get all Windows Driver Profiles and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Windows Driver Update Profiles in Intune to a JSON or YAML file. @@ -50,6 +51,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): continue results["config_count"] += 1 + + if scope_tags: + profile = get_scope_tags_name(profile, scope_tags) if "assignments" not in exclude: assignments = get_object_assignment(profile["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_windowsEnrollmentProfile.py b/src/IntuneCD/backup/Intune/backup_windowsEnrollmentProfile.py index 19210b29..75b64f1f 100644 --- a/src/IntuneCD/backup/Intune/backup_windowsEnrollmentProfile.py +++ b/src/IntuneCD/backup/Intune/backup_windowsEnrollmentProfile.py @@ -10,6 +10,7 @@ from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -18,7 +19,7 @@ # Get all Windows Enrollment Profiles and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Windows Enrollment Profiles in Intune to a JSON or YAML file. @@ -48,6 +49,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): continue results["config_count"] += 1 + + if scope_tags: + profile = get_scope_tags_name(profile, scope_tags) if "assignments" not in exclude: assignments = get_object_assignment(profile["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_windowsFeatureUpdates.py b/src/IntuneCD/backup/Intune/backup_windowsFeatureUpdates.py index 4678623e..9689f163 100644 --- a/src/IntuneCD/backup/Intune/backup_windowsFeatureUpdates.py +++ b/src/IntuneCD/backup/Intune/backup_windowsFeatureUpdates.py @@ -10,6 +10,7 @@ from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -20,7 +21,7 @@ # Get all Windows Feature Profiles and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Windows Feature Update Profiles in Intune to a JSON or YAML file. @@ -50,6 +51,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): continue results["config_count"] += 1 + + if scope_tags: + profile = get_scope_tags_name(profile, scope_tags) if "assignments" not in exclude: assignments = get_object_assignment(profile["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup/Intune/backup_windowsQualityUpdates.py b/src/IntuneCD/backup/Intune/backup_windowsQualityUpdates.py index 19aba458..6fc912bf 100644 --- a/src/IntuneCD/backup/Intune/backup_windowsQualityUpdates.py +++ b/src/IntuneCD/backup/Intune/backup_windowsQualityUpdates.py @@ -10,6 +10,7 @@ from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name from ...intunecdlib.remove_keys import remove_keys from ...intunecdlib.save_output import save_output @@ -20,7 +21,7 @@ # Get all Windows Quality Profiles and save them in specified path -def savebackup(path, output, exclude, token, prefix, append_id, audit): +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): """ Saves all Windows Quality Update Profiles in Intune to a JSON or YAML file. @@ -50,6 +51,9 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit): continue results["config_count"] += 1 + + if scope_tags: + profile = get_scope_tags_name(profile, scope_tags) if "assignments" not in exclude: assignments = get_object_assignment(profile["id"], assignment_responses) if assignments: diff --git a/src/IntuneCD/backup_intune.py b/src/IntuneCD/backup_intune.py index 415cbe62..98746691 100644 --- a/src/IntuneCD/backup_intune.py +++ b/src/IntuneCD/backup_intune.py @@ -1,9 +1,18 @@ # -*- coding: utf-8 -*- + + def backup_intune(results, path, output, exclude, token, prefix, append_id, args): """ Imports all the backup functions and runs them """ + from .intunecdlib.process_scope_tags import get_scope_tags + + if "ScopeTags" not in exclude: + scope_tags = get_scope_tags(token) + else: + scope_tags = None + if args.activationlock: from .backup.Intune.backup_activationLock import savebackup @@ -13,14 +22,18 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args from .backup.Intune.backup_appConfiguration import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "AppProtection" not in exclude: from .backup.Intune.backup_AppProtection import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "APNs" not in exclude: @@ -31,18 +44,24 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args if "VPP" not in exclude: from .backup.Intune.backup_vppTokens import savebackup - results.append(savebackup(path, output, token, append_id, args.audit)) + results.append( + savebackup(path, output, token, append_id, args.audit, scope_tags) + ) if "Applications" not in exclude: from .backup.Intune.backup_applications import savebackup - results.append(savebackup(path, output, exclude, token, append_id, args.audit)) + results.append( + savebackup(path, output, exclude, token, append_id, args.audit, scope_tags) + ) if "Compliance" not in exclude: from .backup.Intune.backup_compliance import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "DeviceManagementSettings" not in exclude: @@ -53,12 +72,16 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args if "DeviceCategories" not in exclude: from .backup.Intune.backup_deviceCategories import savebackup - results.append(savebackup(path, output, token, prefix, append_id, args.audit)) + results.append( + savebackup(path, output, token, prefix, append_id, args.audit, scope_tags) + ) if "NotificationTemplate" not in exclude: from .backup.Intune.backup_notificationTemplate import savebackup - results.append(savebackup(path, output, token, prefix, append_id, args.audit)) + results.append( + savebackup(path, output, token, prefix, append_id, args.audit, scope_tags) + ) if "Profiles" not in exclude: from .backup.Intune.backup_profiles import savebackup @@ -73,6 +96,7 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args append_id, args.ignore_omasettings, args.audit, + scope_tags, ) ) @@ -80,7 +104,9 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args from .backup.Intune.backup_groupPolicyConfiguration import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "AppleEnrollmentProfile" not in exclude: @@ -92,19 +118,25 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args from .backup.Intune.backup_windowsEnrollmentProfile import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "EnrollmentStatusPage" not in exclude: from .backup.Intune.backup_enrollmentStatusPage import savebackup - results.append(savebackup(path, output, exclude, token, prefix, append_id)) + results.append( + savebackup(path, output, exclude, token, prefix, append_id, scope_tags) + ) if "EnrollmentConfigurations" not in exclude: from .backup.Intune.backup_enrollmentConfigurations import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if args.autopilot == "True": @@ -115,7 +147,9 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args if "Filters" not in exclude: from .backup.Intune.backup_assignmentFilters import savebackup - results.append(savebackup(path, output, token, prefix, append_id, args.audit)) + results.append( + savebackup(path, output, token, prefix, append_id, args.audit, scope_tags) + ) if "ManagedGooglePlay" not in exclude: from .backup.Intune.backup_managedGPlay import savebackup @@ -126,7 +160,9 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args from .backup.Intune.backup_managementIntents import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "CompliancePartner" not in exclude: @@ -148,35 +184,45 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args from .backup.Intune.backup_proactiveRemediation import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "PowershellScripts" not in exclude: from .backup.Intune.backup_powershellScripts import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "ShellScripts" not in exclude: from .backup.Intune.backup_shellScripts import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "CustomAttributes" not in exclude: from .backup.Intune.backup_customAttributeShellScript import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "ConfigurationPolicies" not in exclude: from .backup.Intune.backup_configurationPolicies import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "ConditionalAccess" not in exclude: @@ -188,27 +234,35 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args from .backup.Intune.backup_windowsDriverUpdates import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "WindowsFeatureUpdates" not in exclude: from .backup.Intune.backup_windowsFeatureUpdates import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "WindowsQualityUpdates" not in exclude: from .backup.Intune.backup_windowsQualityUpdates import savebackup results.append( - savebackup(path, output, exclude, token, prefix, append_id, args.audit) + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) ) if "Roles" not in exclude: from .backup.Intune.backup_roles import savebackup - results.append(savebackup(path, output, exclude, token, append_id, args.audit)) + results.append( + savebackup(path, output, exclude, token, append_id, args.audit, scope_tags) + ) if "ScopeTags" not in exclude: from .backup.Intune.backup_scopeTags import savebackup diff --git a/src/IntuneCD/intunecdlib/process_scope_tags.py b/src/IntuneCD/intunecdlib/process_scope_tags.py new file mode 100644 index 00000000..bc248c55 --- /dev/null +++ b/src/IntuneCD/intunecdlib/process_scope_tags.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +This module processes the audit data from Intune. +""" + +from .graph_request import makeapirequest +from .logger import log + + +def get_scope_tags(token): + """ + Get scope tags from Intune. + + :param token: Token to use for authenticating the request + """ + endpoint = "https://graph.microsoft.com/beta/deviceManagement/roleScopeTags" + data = makeapirequest(endpoint, token) + return data["value"] + + +def get_scope_tags_name(data, scope_tags): + """ + Get the name of the scope tag. + + :param data: The data to search for the scope tag name + :param scope_tags: The scope tag to search for + """ + + log("get_scope_tags_name", "Checking if scope tags are in the data.") + if data.get("roleScopeTagIds"): + log("get_scope_tags_name", "Scope tags are in the data.") + # list comprehension to get the scope tag name + data["roleScopeTagIds"] = [ + tag["displayName"] + for tag in scope_tags + if tag["id"] in data["roleScopeTagIds"] + ] + log("get_scope_tags_name", f"Scope tags: {data['roleScopeTagIds']}") + + return data + + +def get_scope_tags_id(data, scope_tags): + """ + Get the ID of the scope tag. + + :param data: The data to search for the scope tag ID + :param scope_tags: The scope tag to search for + """ + + log("get_scope_tags_id", "Checking if scope tags are in the data.") + if data.get("roleScopeTagIds"): + log("get_scope_tags_id", "Scope tags are in the data.") + # list comprehension to get the scope tag ID + data["roleScopeTagIds"] = [ + tag["id"] + for tag in scope_tags + if tag["displayName"] in data["roleScopeTagIds"] + ] + log("get_scope_tags_id", f"Scope tags: {data['roleScopeTagIds']}") + + return data diff --git a/src/IntuneCD/update/Intune/update_appConfiguration.py b/src/IntuneCD/update/Intune/update_appConfiguration.py index 62d69ec7..44b46bc9 100644 --- a/src/IntuneCD/update/Intune/update_appConfiguration.py +++ b/src/IntuneCD/update/Intune/update_appConfiguration.py @@ -21,6 +21,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -32,7 +33,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all App Configuration Polices in Intune, @@ -87,6 +94,9 @@ def update( if data["value"]: print("-" * 90) + # Get scope tag ID + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value", {}).get("id", None) # Remove keys before using DeepDiff data = remove_keys(data) diff --git a/src/IntuneCD/update/Intune/update_appProtection.py b/src/IntuneCD/update/Intune/update_appProtection.py index 27a0aa95..2a1f3217 100644 --- a/src/IntuneCD/update/Intune/update_appProtection.py +++ b/src/IntuneCD/update/Intune/update_appProtection.py @@ -20,6 +20,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -28,7 +29,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all App Protection Polices in Intune, @@ -104,6 +111,9 @@ def update( if data["value"]: print("-" * 90) + # Get scope tag ID + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value", {}).get("id", None) # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update/Intune/update_assignmentFilter.py b/src/IntuneCD/update/Intune/update_assignmentFilter.py index da2dc8cb..97dbdedd 100644 --- a/src/IntuneCD/update/Intune/update_assignmentFilter.py +++ b/src/IntuneCD/update/Intune/update_assignmentFilter.py @@ -18,13 +18,14 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys # Set MS Graph endpoint ENDPOINT = "https://graph.microsoft.com/beta/deviceManagement/assignmentFilters" -def update(path, token, report): +def update(path, token, report, scope_tags): """ This function updates all Filters in Intune if the configuration in Intune differs from the JSON/YAML file. @@ -39,7 +40,6 @@ def update(path, token, report): if os.path.exists(configpath): # get all filters mem_data = makeapirequest(ENDPOINT, token) - for filename in os.listdir(configpath): file = check_file(configpath, filename) if file is False: @@ -59,6 +59,8 @@ def update(path, token, report): if filter_value: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) filter_id = filter_value["id"] filter_value = remove_keys(filter_value) diff --git a/src/IntuneCD/update/Intune/update_compliance.py b/src/IntuneCD/update/Intune/update_compliance.py index 80b8f9c1..38379424 100644 --- a/src/IntuneCD/update/Intune/update_compliance.py +++ b/src/IntuneCD/update/Intune/update_compliance.py @@ -20,6 +20,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -28,7 +29,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Compliance Polices in Intune, @@ -85,6 +92,8 @@ def update( if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value", {}).get("id", None) data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update/Intune/update_configurationPolicies.py b/src/IntuneCD/update/Intune/update_configurationPolicies.py index ee6d0457..4953a1b0 100644 --- a/src/IntuneCD/update/Intune/update_configurationPolicies.py +++ b/src/IntuneCD/update/Intune/update_configurationPolicies.py @@ -20,6 +20,7 @@ makeapirequestPut, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from .update_assignment import post_assignment_update, update_assignment # Set MS Graph endpoint @@ -27,7 +28,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Settings Catalog configurations in Intune, @@ -90,6 +97,8 @@ def update( # If Filter exists, continue if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) # Get Filter data from Intune mem_policy_data = makeapirequest( ENDPOINT + "/" + data.get("value").get("id"), token diff --git a/src/IntuneCD/update/Intune/update_customAttributeShellScript.py b/src/IntuneCD/update/Intune/update_customAttributeShellScript.py index b6d407c4..b54e4b02 100644 --- a/src/IntuneCD/update/Intune/update_customAttributeShellScript.py +++ b/src/IntuneCD/update/Intune/update_customAttributeShellScript.py @@ -21,6 +21,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -32,7 +33,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Custom Attribute Shell scripts in Intune if the configuration in Intune differs from the JSON/YAML file. @@ -82,6 +89,8 @@ def update( # If Custom Attribute Shell script exists, continue if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) q_param = None # Get Shell script details mem_data = makeapirequest( diff --git a/src/IntuneCD/update/Intune/update_deviceCategories.py b/src/IntuneCD/update/Intune/update_deviceCategories.py index 029095ee..569b8250 100644 --- a/src/IntuneCD/update/Intune/update_deviceCategories.py +++ b/src/IntuneCD/update/Intune/update_deviceCategories.py @@ -19,13 +19,14 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys # Set MS Graph endpoint ENDPOINT = "https://graph.microsoft.com/beta/deviceManagement/deviceCategories" -def update(path, token, report, remove): +def update(path, token, report, remove, scope_tags): """ This function updates all Device Categories in Intune if the configuration in Intune differs from the JSON/YAML file. @@ -40,7 +41,6 @@ def update(path, token, report, remove): if os.path.exists(configpath): # get all Device Categories mem_data = makeapirequest(ENDPOINT, token) - for filename in os.listdir(configpath): file = check_file(configpath, filename) if file is False: @@ -61,6 +61,8 @@ def update(path, token, report, remove): if category_value: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) category_id = category_value["id"] category_value = remove_keys(category_value) diff --git a/src/IntuneCD/update/Intune/update_enrollmentConfigurations.py b/src/IntuneCD/update/Intune/update_enrollmentConfigurations.py index 6020a942..a4eb484e 100644 --- a/src/IntuneCD/update/Intune/update_enrollmentConfigurations.py +++ b/src/IntuneCD/update/Intune/update_enrollmentConfigurations.py @@ -21,6 +21,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -31,7 +32,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """_summary_ @@ -49,7 +56,6 @@ def update( if os.path.exists(configpath): # Get Enrollment Configurations intune_data = makeapirequest(ENDPOINT, token) - # Get current assignments mem_assignments = batch_assignment( intune_data, @@ -108,6 +114,8 @@ def update( # If Enrollment Configuration exists, continue if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) # Get Enrollment Configuration data from Intune mem_id = data.get("value").get("id") mem_priority = data.get("value").get("priority") diff --git a/src/IntuneCD/update/Intune/update_enrollmentStatusPage.py b/src/IntuneCD/update/Intune/update_enrollmentStatusPage.py index c67e96d9..cf5150ff 100644 --- a/src/IntuneCD/update/Intune/update_enrollmentStatusPage.py +++ b/src/IntuneCD/update/Intune/update_enrollmentStatusPage.py @@ -20,6 +20,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -31,7 +32,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Windows Enrollment Status Page Profiles in Intune, @@ -84,6 +91,8 @@ def update( # If Enrollment Status Page Profile exists, continue if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value").get("id") # Remove keys before using DeepDiff mem_data["value"][0] = remove_keys(mem_data["value"][0]) diff --git a/src/IntuneCD/update/Intune/update_groupPolicyConfiguration.py b/src/IntuneCD/update/Intune/update_groupPolicyConfiguration.py index 9cfa3fba..70248744 100644 --- a/src/IntuneCD/update/Intune/update_groupPolicyConfiguration.py +++ b/src/IntuneCD/update/Intune/update_groupPolicyConfiguration.py @@ -20,6 +20,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -358,7 +359,13 @@ def update_definition(repo_data, data, mem_id, mem_def_ids, token, report=False) def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Group Policy configurations in Intune, @@ -438,6 +445,8 @@ def update( # If data was found, continue if data: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data["id"] data = remove_keys(data) diff --git a/src/IntuneCD/update/Intune/update_managementIntents.py b/src/IntuneCD/update/Intune/update_managementIntents.py index 46c16bbb..8ffee9dc 100644 --- a/src/IntuneCD/update/Intune/update_managementIntents.py +++ b/src/IntuneCD/update/Intune/update_managementIntents.py @@ -23,6 +23,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from .update_assignment import post_assignment_update, update_assignment # Set MS Graph base endpoint @@ -30,7 +31,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=False, ): """ This function updates all Endpoint Security configurations (intents) in Intune, @@ -91,6 +98,8 @@ def update( # If Intent exists, continue if mem_data: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) print( "Checking if Intent: " + repo_data["displayName"] diff --git a/src/IntuneCD/update/Intune/update_notificationTemplate.py b/src/IntuneCD/update/Intune/update_notificationTemplate.py index a7b669ea..2006bf07 100644 --- a/src/IntuneCD/update/Intune/update_notificationTemplate.py +++ b/src/IntuneCD/update/Intune/update_notificationTemplate.py @@ -19,6 +19,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys # Set MS Graph endpoint @@ -27,7 +28,7 @@ ) -def update(path, token, report, remove): +def update(path, token, report, remove, scope_tags): """ This function updates all Notification Templates in Intune, if the configuration in Intune differs from the JSON/YAML file. @@ -65,6 +66,10 @@ def update(path, token, report, remove): # If Notification Template exists, continue if data["value"]: print("-" * 90) + if scope_tags: + repo_data["roleScopeTagIds"] = get_scope_tags_id( + repo_data, scope_tags + ) # Get Notification Template data from Intune q_param = "?$expand=localizedNotificationMessages" mem_template_data = makeapirequest( diff --git a/src/IntuneCD/update/Intune/update_powershellScripts.py b/src/IntuneCD/update/Intune/update_powershellScripts.py index 99a5d6d2..8845c32d 100644 --- a/src/IntuneCD/update/Intune/update_powershellScripts.py +++ b/src/IntuneCD/update/Intune/update_powershellScripts.py @@ -21,6 +21,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -29,7 +30,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Powershell scripts in Intune if, @@ -80,6 +87,8 @@ def update( # If Powershell script exists, continue if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) # Get Powershell script details mem_data = makeapirequest( ENDPOINT + "/" + data.get("value").get("id"), token diff --git a/src/IntuneCD/update/Intune/update_proactiveRemediation.py b/src/IntuneCD/update/Intune/update_proactiveRemediation.py index 5414c054..b3d96386 100644 --- a/src/IntuneCD/update/Intune/update_proactiveRemediation.py +++ b/src/IntuneCD/update/Intune/update_proactiveRemediation.py @@ -21,6 +21,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -29,7 +30,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Proactive Remediation in Intune if, @@ -80,6 +87,8 @@ def update( # If Powershell script exists, continue if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) q_param = None # Get Powershell script details mem_data = makeapirequest( diff --git a/src/IntuneCD/update/Intune/update_profiles.py b/src/IntuneCD/update/Intune/update_profiles.py index 3bc4a764..13b4aec7 100644 --- a/src/IntuneCD/update/Intune/update_profiles.py +++ b/src/IntuneCD/update/Intune/update_profiles.py @@ -23,6 +23,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -31,7 +32,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Device Configurations in Intune, @@ -80,6 +87,8 @@ def update( if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value").get("id") # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update/Intune/update_roles.py b/src/IntuneCD/update/Intune/update_roles.py index 4e609c64..1db6bd83 100644 --- a/src/IntuneCD/update/Intune/update_roles.py +++ b/src/IntuneCD/update/Intune/update_roles.py @@ -19,13 +19,14 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys # Set MS Graph endpoint ENDPOINT = "https://graph.microsoft.com/beta/deviceManagement/roleDefinitions" -def update(path, token, report, remove=False): +def update(path, token, report, remove=False, scope_tags=None): """ This function updates all Roles in Intune if the configuration in Intune differs from the JSON/YAML file. @@ -62,6 +63,8 @@ def update(path, token, report, remove=False): if role_value: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) role_id = role_value["id"] role_value = remove_keys(role_value) diff --git a/src/IntuneCD/update/Intune/update_scopeTags.py b/src/IntuneCD/update/Intune/update_scopeTags.py index c5568c32..36aa9d4a 100644 --- a/src/IntuneCD/update/Intune/update_scopeTags.py +++ b/src/IntuneCD/update/Intune/update_scopeTags.py @@ -130,7 +130,7 @@ def update( token, q_param=None, jdata=request_json, - status_code=201, + status_code=200, ) mem_assign_obj = [] assignment = update_assignment( diff --git a/src/IntuneCD/update/Intune/update_shellScripts.py b/src/IntuneCD/update/Intune/update_shellScripts.py index f7938ebf..44be42f7 100644 --- a/src/IntuneCD/update/Intune/update_shellScripts.py +++ b/src/IntuneCD/update/Intune/update_shellScripts.py @@ -21,6 +21,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -32,7 +33,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Shell scripts in Intune if the configuration in Intune differs from the JSON/YAML file. @@ -43,7 +50,7 @@ def update( """ diff_summary = [] - # Set Shell scritp path + # Set Shell script path configpath = path + "/" + "Scripts/Shell" # If Shell script path exists, continue if os.path.exists(configpath): @@ -82,6 +89,8 @@ def update( # If Shell script exists, continue if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) q_param = None # Get Shell script details mem_data = makeapirequest( diff --git a/src/IntuneCD/update/Intune/update_windowsDriverUpdates.py b/src/IntuneCD/update/Intune/update_windowsDriverUpdates.py index e50f0646..fb0f9c35 100644 --- a/src/IntuneCD/update/Intune/update_windowsDriverUpdates.py +++ b/src/IntuneCD/update/Intune/update_windowsDriverUpdates.py @@ -20,6 +20,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -30,7 +31,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Windows Driver Update Profiles in Intune, @@ -81,6 +88,8 @@ def update( # If Windows Driver Update Profile exists, continue if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value").get("id") # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update/Intune/update_windowsEnrollmentProfile.py b/src/IntuneCD/update/Intune/update_windowsEnrollmentProfile.py index 470fc22f..38b7dca5 100644 --- a/src/IntuneCD/update/Intune/update_windowsEnrollmentProfile.py +++ b/src/IntuneCD/update/Intune/update_windowsEnrollmentProfile.py @@ -20,6 +20,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -28,7 +29,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Windows Enrollment Profiles in Intune, @@ -79,6 +86,8 @@ def update( # If Windows Enrollment Profile exists, continue if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value").get("id") # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update/Intune/update_windowsFeatureUpdates.py b/src/IntuneCD/update/Intune/update_windowsFeatureUpdates.py index 6dbd9101..d4f931ed 100644 --- a/src/IntuneCD/update/Intune/update_windowsFeatureUpdates.py +++ b/src/IntuneCD/update/Intune/update_windowsFeatureUpdates.py @@ -20,6 +20,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -30,7 +31,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Windows Feature Update Profiles in Intune, @@ -81,6 +88,8 @@ def update( # If Windows Feature Update Profile exists, continue if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value").get("id") # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update/Intune/update_windowsQualityUpdates.py b/src/IntuneCD/update/Intune/update_windowsQualityUpdates.py index 69d7a514..df5ee8d4 100644 --- a/src/IntuneCD/update/Intune/update_windowsQualityUpdates.py +++ b/src/IntuneCD/update/Intune/update_windowsQualityUpdates.py @@ -20,6 +20,7 @@ makeapirequestPost, ) from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id from ...intunecdlib.remove_keys import remove_keys from .update_assignment import post_assignment_update, update_assignment @@ -30,7 +31,13 @@ def update( - path, token, assignment=False, report=False, create_groups=False, remove=False + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, ): """ This function updates all Windows Quality Update Profiles in Intune, @@ -81,6 +88,8 @@ def update( # If Windows Quality Update Profile exists, continue if data["value"]: print("-" * 90) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value").get("id") # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update_intune.py b/src/IntuneCD/update_intune.py index 46319c5d..b560cc8c 100644 --- a/src/IntuneCD/update_intune.py +++ b/src/IntuneCD/update_intune.py @@ -15,32 +15,37 @@ def update_intune( Imports all the update functions and runs them """ + from .intunecdlib.process_scope_tags import get_scope_tags + if "ScopeTags" not in exclude: from .update.Intune.update_scopeTags import update diff_summary.append( update(path, token, assignment, report, create_groups, remove) ) + scope_tags = get_scope_tags(token) + else: + scope_tags = None if "AppConfigurations" not in exclude: from .update.Intune.update_appConfiguration import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "AppProtection" not in exclude: from .update.Intune.update_appProtection import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "Compliance" not in exclude: from .update.Intune.update_compliance import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "DeviceManagementSettings" not in exclude and args.interactiveauth is True: @@ -56,25 +61,25 @@ def update_intune( if "DeviceCategories" not in exclude: from .update.Intune.update_deviceCategories import update - diff_summary.append(update(path, token, report, remove)) + diff_summary.append(update(path, token, report, remove, scope_tags)) if "NotificationTemplate" not in exclude: from .update.Intune.update_notificationTemplate import update - diff_summary.append(update(path, token, report, remove)) + diff_summary.append(update(path, token, report, remove, scope_tags)) if "Profiles" not in exclude: from .update.Intune.update_profiles import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "GPOConfigurations" not in exclude: from .update.Intune.update_groupPolicyConfiguration import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "AppleEnrollmentProfile" not in exclude: @@ -86,7 +91,7 @@ def update_intune( from .update.Intune.update_windowsEnrollmentProfile import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "EnrollmentStatusPage" not in exclude: @@ -100,54 +105,54 @@ def update_intune( from .update.Intune.update_enrollmentConfigurations import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "Filters" not in exclude: from .update.Intune.update_assignmentFilter import update - diff_summary.append(update(path, token, report)) + diff_summary.append(update(path, token, report, scope_tags)) if "Intents" not in exclude: from .update.Intune.update_managementIntents import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "ProactiveRemediation" not in exclude: from .update.Intune.update_proactiveRemediation import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "PowershellScripts" not in exclude: from .update.Intune.update_powershellScripts import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "ShellScripts" not in exclude: from .update.Intune.update_shellScripts import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "CustomAttribute" not in exclude: from .update.Intune.update_customAttributeShellScript import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "ConfigurationPolicies" not in exclude: from .update.Intune.update_configurationPolicies import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "ConditionalAccess" not in exclude: @@ -159,24 +164,24 @@ def update_intune( from .update.Intune.update_windowsDriverUpdates import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "windowsFeatureUpdates" not in exclude: from .update.Intune.update_windowsFeatureUpdates import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "windowsQualityUpdates" not in exclude: from .update.Intune.update_windowsQualityUpdates import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "Roles" not in exclude: from .update.Intune.update_roles import update - diff_summary.append(update(path, token, report, remove)) + diff_summary.append(update(path, token, report, remove, scope_tags)) diff --git a/tests/Backup/Intune/test_backup_appProtection.py b/tests/Backup/Intune/test_backup_appProtection.py index 24b39f93..66f5f7ca 100644 --- a/tests/Backup/Intune/test_backup_appProtection.py +++ b/tests/Backup/Intune/test_backup_appProtection.py @@ -64,6 +64,19 @@ def setUp(self): } ], } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_AppProtection.batch_assignment" @@ -83,11 +96,18 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.app_protection + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_AppProtection.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -100,6 +120,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -121,6 +142,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -146,6 +168,7 @@ def test_backup_targetedManagedAppConfiguration(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -163,6 +186,7 @@ def test_backup_targetedAppManagementLevels(self): "", self.append_id, False, + None, ) with open( @@ -186,6 +210,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -200,6 +225,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -207,7 +233,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None ) self.assertTrue( @@ -216,6 +242,26 @@ def test_backup_append_id(self): ).exists() ) + def test_backup_scope_tag_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + False, + True, + [{"id": 0, "displayName": "default"}], + ) + + with open(self.saved_path + "json", "r", encoding="utf-8") as f: + self.saved_data = json.load(f) + + self.assertTrue(Path(f"{self.directory.path}/App Protection").exists()) + self.assertEqual(1, self.count["config_count"]) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_applications.py b/tests/Backup/Intune/test_backup_applications.py index 70a8aefc..75a5a9ca 100644 --- a/tests/Backup/Intune/test_backup_applications.py +++ b/tests/Backup/Intune/test_backup_applications.py @@ -46,6 +46,19 @@ def setUp(self): } ] self.object_assignment_data = [{"target": {"groupName": "Group1"}}] + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_applications.batch_assignment" @@ -64,11 +77,18 @@ def setUp(self): ) self.makeapirequest = self.makeapirequest_patch.start() + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_applications.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_ios_vpp_app(self): """The folder should be created, the file should be created, and the count should be 1.""" @@ -77,7 +97,13 @@ def test_backup_ios_vpp_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id, False + self.directory.path, + "json", + self.exclude, + self.token, + self.append_id, + False, + False, ) self.assertTrue(Path(self.directory.path + "/Applications/iOS").exists()) @@ -95,7 +121,13 @@ def test_backup_macOS_vpp_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id, False + self.directory.path, + "json", + self.exclude, + self.token, + self.append_id, + False, + False, ) self.assertTrue(Path(self.directory.path + "/Applications/macOS").exists()) @@ -117,7 +149,13 @@ def test_backup_vpp_app_exclude_licensecount(self): self.exclude = ["VPPusedLicenseCount"] self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id, False + self.directory.path, + "json", + self.exclude, + self.token, + self.append_id, + False, + False, ) app_data = json.load( @@ -137,7 +175,13 @@ def test_backup_win32_lob_app_and_displayVersion(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id, False + self.directory.path, + "json", + self.exclude, + self.token, + self.append_id, + False, + False, ) self.assertTrue(Path(self.directory.path + "/Applications/Windows").exists()) @@ -156,7 +200,13 @@ def test_backup_win32_lob_app_no_displayVersion(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id, False + self.directory.path, + "json", + self.exclude, + self.token, + self.append_id, + False, + False, ) self.assertTrue(Path(self.directory.path + "/Applications/Windows").exists()) @@ -175,7 +225,13 @@ def test_backup_msi_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id, False + self.directory.path, + "json", + self.exclude, + self.token, + self.append_id, + False, + False, ) self.assertTrue(Path(self.directory.path + "/Applications/Windows").exists()) @@ -195,7 +251,13 @@ def test_backup_android_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id, False + self.directory.path, + "json", + self.exclude, + self.token, + self.append_id, + False, + False, ) self.assertTrue(Path(self.directory.path + "/Applications/Android").exists()) @@ -214,7 +276,13 @@ def test_backup_microsoft_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id, False + self.directory.path, + "json", + self.exclude, + self.token, + self.append_id, + False, + False, ) self.assertTrue(Path(self.directory.path + "/Applications/Windows").exists()) @@ -234,7 +302,13 @@ def test_backup_office_suite_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id, False + self.directory.path, + "json", + self.exclude, + self.token, + self.append_id, + False, + False, ) self.assertTrue( @@ -255,7 +329,13 @@ def test_backup_web_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id, False + self.directory.path, + "json", + self.exclude, + self.token, + self.append_id, + False, + False, ) self.assertTrue(Path(self.directory.path + "/Applications/Web App").exists()) @@ -273,7 +353,13 @@ def test_backup_other_app(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id, False + self.directory.path, + "json", + self.exclude, + self.token, + self.append_id, + False, + False, ) self.assertTrue(Path(self.directory.path + "/Applications/macOS").exists()) @@ -288,7 +374,13 @@ def test_backup_with_no_returned_data(self): """The count should be 0 if no data is returned.""" self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, self.append_id, False + self.directory.path, + "json", + self.exclude, + self.token, + self.append_id, + False, + False, ) self.assertEqual(0, self.count["config_count"]) @@ -299,7 +391,28 @@ def test_backup_append_id(self): self.makeapirequest.return_value = self.app_base_data self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, True, False + self.directory.path, "json", self.exclude, self.token, True, False, False + ) + + self.assertTrue( + Path( + self.directory.path + "/Applications/iOS/test_iOSVppApp_test__0.json" + ).exists() + ) + + def test_backup_scope_tag_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + self.app_base_data["value"][0]["@odata.type"] = "#microsoft.graph.iosVppApp" + self.makeapirequest.return_value = self.app_base_data + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + True, + False, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_assignmentFilter.py b/tests/Backup/Intune/test_backup_assignmentFilter.py index fd48dc5f..a5ea80c1 100644 --- a/tests/Backup/Intune/test_backup_assignmentFilter.py +++ b/tests/Backup/Intune/test_backup_assignmentFilter.py @@ -42,6 +42,19 @@ def setUp(self): } ] } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.patch_makeapirequest = patch( "src.IntuneCD.backup.Intune.backup_assignmentFilters.makeapirequest", @@ -49,15 +62,22 @@ def setUp(self): ) self.makeapirequest = self.patch_makeapirequest.start() + self.makeAuditRequest = patch( + "src.IntuneCD.backup.Intune.backup_assignmentFilters.makeAuditRequest", + return_value=self.audit_data, + ) + self.makeAuditRequest = self.makeAuditRequest.start() + def tearDown(self): self.directory.cleanup() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.token, "", self.append_id, False + self.directory.path, "yaml", self.token, "", self.append_id, False, "" ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -72,7 +92,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id, False + self.directory.path, "json", self.token, "", self.append_id, False, "" ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -87,7 +107,7 @@ def test_backup_with_no_return_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id, False + self.directory.path, "json", self.token, "", self.append_id, False, "" ) self.assertEqual(0, self.count["config_count"]) @@ -96,7 +116,7 @@ def test_backup_with_prefix(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.token, "test", self.append_id, False + self.directory.path, "json", self.token, "test", self.append_id, False, "" ) self.assertEqual(0, self.count["config_count"]) @@ -104,13 +124,29 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.token, "", True, False + self.directory.path, "json", self.token, "", True, False, "" ) self.assertTrue( Path(f"{self.directory.path}/Filters/macOS - Model__0.json").exists() ) + def test_backup_scope_tag_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + self.count = savebackup( + self.directory.path, + "json", + self.token, + "", + True, + False, + [{"id": 0, "displayName": "default"}], + ) + self.assertTrue( + Path(f"{self.directory.path}/Filters/macOS - Model__0.json").exists() + ) + self.assertEqual(1, self.count["config_count"]) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_compliance.py b/tests/Backup/Intune/test_backup_compliance.py index 496edfb8..87d1f9cd 100644 --- a/tests/Backup/Intune/test_backup_compliance.py +++ b/tests/Backup/Intune/test_backup_compliance.py @@ -59,6 +59,19 @@ def setUp(self): } ] } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_compliance.batch_assignment" @@ -78,11 +91,18 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.compliance_policy + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_compliance.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -96,6 +116,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -120,6 +141,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -143,6 +165,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -158,6 +181,7 @@ def test_backup_with_prefix(self): "test", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -165,7 +189,27 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Compliance Policies/Policies/test_iosCompliancePolicy__0.json" + ).exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + False, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_configurationPolicies.py b/tests/Backup/Intune/test_backup_configurationPolicies.py index 72dd9938..5e34902b 100644 --- a/tests/Backup/Intune/test_backup_configurationPolicies.py +++ b/tests/Backup/Intune/test_backup_configurationPolicies.py @@ -92,6 +92,19 @@ def setUp(self): } ] } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_configurationPolicies.batch_assignment" @@ -117,12 +130,19 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.configuration_policy + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_configurationPolicies.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.batch_request.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -135,6 +155,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -156,6 +177,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -177,6 +199,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -192,6 +215,7 @@ def test_backup_with_prefix(self): "test", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -199,13 +223,32 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None ) self.assertTrue( Path(f"{self.directory.path}/Settings Catalog/test_test__0.json").exists() ) + def test_backup_scope_tag_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + False, + [{"id": 0, "displayName": "default"}], + ) + + self.assertTrue( + Path(f"{self.directory.path}/Settings Catalog/test_test__0.json").exists() + ) + self.assertEqual(1, self.count["config_count"]) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_customAttributeShellScript.py b/tests/Backup/Intune/test_backup_customAttributeShellScript.py index 0f12fe3a..44e54b28 100644 --- a/tests/Backup/Intune/test_backup_customAttributeShellScript.py +++ b/tests/Backup/Intune/test_backup_customAttributeShellScript.py @@ -45,6 +45,19 @@ def setUp(self): "scriptContent": "WW91IGZvdW5kIGEgc2VjcmV0IG1lc3NhZ2UsIGhvb3JheSE=", } ] + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_customAttributeShellScript.batch_assignment" @@ -70,12 +83,19 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.script_policy_data + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_customAttributeShellScript.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.batch_request.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -88,6 +108,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -109,6 +130,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -129,6 +151,7 @@ def test_script_is_created(self): "", self.append_id, False, + None, ) self.assertTrue(f"{self.directory.path}/Custom Attributes/Script Data") @@ -147,6 +170,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -162,6 +186,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -170,7 +195,25 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None + ) + + self.assertTrue( + Path(f"{self.directory.path}/Custom Attributes/test__0.json").exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_deviceCategories.py b/tests/Backup/Intune/test_backup_deviceCategories.py index d5dc98f0..ec5f2f1d 100644 --- a/tests/Backup/Intune/test_backup_deviceCategories.py +++ b/tests/Backup/Intune/test_backup_deviceCategories.py @@ -39,6 +39,19 @@ def setUp(self): } ] } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.patch_makeapirequest = patch( "src.IntuneCD.backup.Intune.backup_deviceCategories.makeapirequest", @@ -46,15 +59,23 @@ def setUp(self): ) self.makeapirequest = self.patch_makeapirequest.start() + self.makeAuditRequest = patch( + "src.IntuneCD.backup.Intune.backup_deviceCategories.makeAuditRequest", + return_value=self.audit_data, + ) + self.makeAuditRequest.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.token, "", self.append_id, False + self.directory.path, "yaml", self.token, "", self.append_id, False, "" ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -69,7 +90,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id, False + self.directory.path, "json", self.token, "", self.append_id, False, "" ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -84,7 +105,7 @@ def test_backup_with_no_return_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id, False + self.directory.path, "json", self.token, "", self.append_id, False, "" ) self.assertEqual(0, self.count["config_count"]) @@ -93,7 +114,7 @@ def test_backup_with_prefix(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.token, "test", self.append_id, False + self.directory.path, "json", self.token, "test", self.append_id, False, "" ) self.assertEqual(0, self.count["config_count"]) @@ -101,7 +122,26 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.token, "", True, False + self.directory.path, "json", self.token, "", True, False, "" + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Device Categories/Test__00000000-0000-0000-0000-000000000000.json" + ).exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_enrollmentConfigurations.py b/tests/Backup/Intune/test_backup_enrollmentConfigurations.py index ad5cee08..157f973c 100644 --- a/tests/Backup/Intune/test_backup_enrollmentConfigurations.py +++ b/tests/Backup/Intune/test_backup_enrollmentConfigurations.py @@ -50,6 +50,19 @@ def setUp(self): } ] } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_enrollmentConfigurations.batch_assignment" @@ -69,11 +82,18 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.enrollment_config + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_enrollmentConfigurations.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """Test that the backup is saved as yml. And that the data is correct.""" @@ -86,6 +106,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(f"{self.saved_path}yaml", "r", encoding="utf-8") as file: data = yaml.safe_load(file) @@ -102,6 +123,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(f"{self.saved_path}json", "r", encoding="utf-8") as file: data = yaml.safe_load(file) @@ -121,6 +143,7 @@ def test_backup_skip_ESP(self): "", self.append_id, False, + None, ) self.assertEqual(0, count["config_count"]) @@ -137,6 +160,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -152,6 +176,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -159,7 +184,27 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Enrollment Configurations/test_test__test.json" + ).exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_enrollmentStatusPage.py b/tests/Backup/Intune/test_backup_enrollmentStatusPage.py index fc1682ef..31721a8c 100644 --- a/tests/Backup/Intune/test_backup_enrollmentStatusPage.py +++ b/tests/Backup/Intune/test_backup_enrollmentStatusPage.py @@ -72,14 +72,19 @@ def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() - self.makeapirequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" output = "yaml" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + None, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -95,7 +100,13 @@ def test_backup_json(self): output = "json" count = savebackup( - self.directory.path, output, self.exclude, self.token, "", self.append_id + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + None, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -110,7 +121,13 @@ def test_backup_with_no_returned_data(self): self.makeapirequest.side_effect = [{"value": []}] self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", self.append_id + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -125,6 +142,7 @@ def test_backup_with_prefix(self): self.token, "test1", self.append_id, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -132,7 +150,26 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True + self.directory.path, "json", self.exclude, self.token, "", True, None + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Enrollment Profiles/Windows/ESP/test__0.json" + ).exists() + ) + + def test_backup_scope_tags(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_groupPolicyConfiguration.py b/tests/Backup/Intune/test_backup_groupPolicyConfiguration.py index 1cb59b1a..baf52dc3 100644 --- a/tests/Backup/Intune/test_backup_groupPolicyConfiguration.py +++ b/tests/Backup/Intune/test_backup_groupPolicyConfiguration.py @@ -65,6 +65,19 @@ def setUp(self): ] } self.presentations = {"value": []} + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_groupPolicyConfiguration.batch_assignment" @@ -88,11 +101,18 @@ def setUp(self): self.presentations, ) + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_groupPolicyConfiguration.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -105,6 +125,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -128,6 +149,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -151,6 +173,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -166,6 +189,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -173,7 +197,27 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Group Policy Configurations/test__0.json" + ).exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_managementIntents.py b/tests/Backup/Intune/test_backup_managementIntents.py index c99fd661..f51c5dfd 100644 --- a/tests/Backup/Intune/test_backup_managementIntents.py +++ b/tests/Backup/Intune/test_backup_managementIntents.py @@ -63,6 +63,19 @@ def setUp(self): } ] } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_intent_patch = patch( "src.IntuneCD.backup.Intune.backup_managementIntents.batch_intents" @@ -88,12 +101,19 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.side_effect = self.intent, self.template + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_managementIntents.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() self.batch_intent.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -106,6 +126,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -129,6 +150,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -152,6 +174,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -167,6 +190,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -174,7 +198,27 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Management Intents/Dummy Intent/test__0.json" + ).exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_notificationTemplate.py b/tests/Backup/Intune/test_backup_notificationTemplate.py index 428a5b4c..7fc2cbe7 100644 --- a/tests/Backup/Intune/test_backup_notificationTemplate.py +++ b/tests/Backup/Intune/test_backup_notificationTemplate.py @@ -77,6 +77,19 @@ def setUp(self): } ], } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.patch_makeapirequest = patch( "src.IntuneCD.backup.Intune.backup_notificationTemplate.makeapirequest", @@ -84,15 +97,22 @@ def setUp(self): ) self.makeapirequest = self.patch_makeapirequest.start() + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_notificationTemplate.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.token, "", self.append_id, False + self.directory.path, "yaml", self.token, "", self.append_id, False, "" ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -111,7 +131,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id, False + self.directory.path, "json", self.token, "", self.append_id, False, "" ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -130,7 +150,7 @@ def test_backup_with_no_return_data(self): self.makeapirequest.side_effect = [{"value": []}] self.count = savebackup( - self.directory.path, "json", self.token, "", self.append_id, False + self.directory.path, "json", self.token, "", self.append_id, False, "" ) self.assertEqual(0, self.count["config_count"]) @@ -138,7 +158,7 @@ def test_backup_with_prefix(self): """The count should be 0 if no data is returned.""" self.count = savebackup( - self.directory.path, "json", self.token, "test1", self.append_id, False + self.directory.path, "json", self.token, "test1", self.append_id, False, "" ) self.assertEqual(0, self.count["config_count"]) @@ -146,7 +166,26 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.token, "", True, False + self.directory.path, "json", self.token, "", True, False, "" + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Compliance Policies/Message Templates/test__0.json" + ).exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_powershellScripts.py b/tests/Backup/Intune/test_backup_powershellScripts.py index 142246e1..c76d10da 100644 --- a/tests/Backup/Intune/test_backup_powershellScripts.py +++ b/tests/Backup/Intune/test_backup_powershellScripts.py @@ -45,6 +45,19 @@ def setUp(self): "scriptContent": "WW91IGZvdW5kIGEgc2VjcmV0IG1lc3NhZ2UsIGhvb3JheSE=", } ] + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_powershellScripts.batch_assignment" @@ -70,12 +83,19 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.script_policy_data + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_powershellScripts.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.batch_request.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -88,6 +108,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -109,6 +130,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -129,6 +151,7 @@ def test_script_is_created(self): "", self.append_id, False, + None, ) self.assertTrue( @@ -149,6 +172,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -164,6 +188,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -171,7 +196,30 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None + ) + + self.assertTrue( + Path(f"{self.directory.path}/Scripts/Powershell/test__0.json").exists() + ) + self.assertTrue( + Path( + f"{self.directory.path}/Scripts/Powershell/Script Data/test__0.ps1" + ).exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_proactiveRemediation.py b/tests/Backup/Intune/test_backup_proactiveRemediation.py index 8c3f9fc8..81639c56 100644 --- a/tests/Backup/Intune/test_backup_proactiveRemediation.py +++ b/tests/Backup/Intune/test_backup_proactiveRemediation.py @@ -46,6 +46,19 @@ def setUp(self): "remediationScriptContent": "WW91IGZvdW5kIGEgc2VjcmV0IG1lc3NhZ2UsIGhvb3JheSE=", } ] + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_proactiveRemediation.batch_assignment" @@ -71,12 +84,19 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.script_policy_data + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_proactiveRemediation.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.batch_request.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -89,6 +109,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -110,6 +131,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -130,6 +152,7 @@ def test_detection_script_is_created(self): "", self.append_id, False, + None, ) self.assertTrue(f"{self.directory.path}/Proactive Remediations/Script Data") @@ -146,6 +169,7 @@ def test_remediation_script_is_created(self): "", self.append_id, False, + None, ) self.assertTrue(f"{self.directory.path}/Proactive Remediations/Script Data") @@ -166,6 +190,7 @@ def test_publisher_is_microsoft(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -185,6 +210,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -200,6 +226,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -207,7 +234,30 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None + ) + + self.assertTrue( + Path(f"{self.directory.path}/Proactive Remediations/test__0.json").exists() + ) + self.assertTrue( + Path( + f"{self.directory.path}/Proactive Remediations/Script Data/test_DetectionScript__0.ps1" + ).exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_profiles.py b/tests/Backup/Intune/test_backup_profiles.py index 8a56c6cc..2ca7a623 100644 --- a/tests/Backup/Intune/test_backup_profiles.py +++ b/tests/Backup/Intune/test_backup_profiles.py @@ -26,6 +26,20 @@ def setUp(self): self.exclude = [] self.append_id = False + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } + self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_profiles.batch_assignment" ) @@ -43,11 +57,18 @@ def setUp(self): ) self.makeapirequest = self.makeapirequest_patch.start() + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_profiles.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_macOS_custom_profile(self): """The folders and files should be created and the count should be 2.""" @@ -73,6 +94,7 @@ def test_backup_macOS_custom_profile(self): self.append_id, False, False, + None, ) self.assertTrue( @@ -111,6 +133,7 @@ def test_backup_ios_custom_profile(self): self.append_id, False, False, + None, ) self.assertTrue( @@ -164,6 +187,7 @@ def test_backup_windows_custom_profile_encrypted(self): self.append_id, False, False, + None, ) self.assertTrue( @@ -212,6 +236,7 @@ def test_backup_windows_custom_profile_not_encrypted(self): self.append_id, False, False, + None, ) self.assertTrue( @@ -221,6 +246,33 @@ def test_backup_windows_custom_profile_not_encrypted(self): ) self.assertEqual(1, self.count["config_count"]) + def test_backup_scope_tags_and_audit(self): + """The folders and files should be created and the count should be 2.""" + + self.makeapirequest.return_value = { + "value": [ + { + "@odata.type": "#microsoft.graph.test", + "id": "0", + "displayName": "test", + } + ] + } + + self.count = savebackup( + self.directory.path, + "json", + self.token, + self.exclude, + "", + self.append_id, + False, + False, + [{"id": 0, "displayName": "default"}], + ) + + self.assertEqual(1, self.count["config_count"]) + class TestBackupStandardProfiles(unittest.TestCase): """Test class for backup_profiles.""" @@ -232,6 +284,20 @@ def setUp(self): self.exclude = [] self.append_id = False + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } + self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_profiles.batch_assignment" ) @@ -249,11 +315,18 @@ def setUp(self): ) self.makeapirequest = self.makeapirequest_patch.start() + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_profiles.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_non_custom_profile(self): """The file should be created and the count should be 1.""" @@ -277,6 +350,7 @@ def test_backup_non_custom_profile(self): self.append_id, False, False, + None, ) self.assertTrue( @@ -298,6 +372,7 @@ def test_backup_with_prefix(self): self.append_id, False, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -322,6 +397,7 @@ def test_backup_append_id(self): True, False, False, + None, ) self.assertTrue( @@ -330,6 +406,32 @@ def test_backup_append_id(self): ).exists() ) + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + self.makeapirequest.return_value = { + "value": [ + { + "@odata.type": "#microsoft.graph.macOSGeneralDeviceConfiguration", + "id": "0", + "displayName": "test", + } + ] + } + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, + True, + [{"id": 0, "displayName": "default"}], + ) + + self.assertEqual(1, self.count["config_count"]) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_roles.py b/tests/Backup/Intune/test_backup_roles.py index 8721cbcb..213c3a87 100644 --- a/tests/Backup/Intune/test_backup_roles.py +++ b/tests/Backup/Intune/test_backup_roles.py @@ -92,6 +92,19 @@ def setUp(self): } ] } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.patch_makeapirequest = patch( "src.IntuneCD.backup.Intune.backup_roles.makeapirequest", @@ -105,15 +118,22 @@ def setUp(self): ) self.makeapirequest = self.patch_makeapirequest.start() + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_roles.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", "", self.token, self.append_id, False + self.directory.path, "yaml", "", self.token, self.append_id, False, None ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -128,7 +148,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", "", self.token, self.append_id, False + self.directory.path, "json", "", self.token, self.append_id, False, None ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -143,7 +163,7 @@ def test_backup_with_no_return_data(self): self.makeapirequest.side_effect = [{"value": []}, {"value": []}, {"value": []}] self.count = savebackup( - self.directory.path, "json", "", self.token, self.append_id, False + self.directory.path, "json", "", self.token, self.append_id, False, None ) self.assertEqual(0, self.count["config_count"]) @@ -151,7 +171,22 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", "", self.token, True, False + self.directory.path, "json", "", self.token, True, False, None + ) + + self.assertTrue(Path(f"{self.directory.path}/Roles/test__0.json").exists()) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + "", + self.token, + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue(Path(f"{self.directory.path}/Roles/test__0.json").exists()) diff --git a/tests/Backup/Intune/test_backup_shellScripts.py b/tests/Backup/Intune/test_backup_shellScripts.py index 3f65fa45..a8e79a9e 100644 --- a/tests/Backup/Intune/test_backup_shellScripts.py +++ b/tests/Backup/Intune/test_backup_shellScripts.py @@ -45,6 +45,19 @@ def setUp(self): "scriptContent": "WW91IGZvdW5kIGEgc2VjcmV0IG1lc3NhZ2UsIGhvb3JheSE=", } ] + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_shellScripts.batch_assignment" @@ -70,12 +83,19 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.script_policy_data + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_shellScripts.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.batch_request.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -88,6 +108,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -109,6 +130,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -129,6 +151,7 @@ def test_script_is_created(self): "", self.append_id, False, + None, ) self.assertTrue(f"{self.directory.path}/Scripts/Shell/Script Data") @@ -147,6 +170,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -162,6 +186,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -169,7 +194,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None ) self.assertTrue( @@ -179,6 +204,25 @@ def test_backup_append_id(self): Path(f"{self.directory.path}/Scripts/Shell/Script Data/test__0.sh").exists() ) + def test_backup_scope_tag_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + False, + [{"id": 0, "displayName": "default"}], + ) + + self.assertTrue( + Path(f"{self.directory.path}/Scripts/Shell/test__0.json").exists() + ) + self.assertEqual(1, self.count["config_count"]) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_vppTokens.py b/tests/Backup/Intune/test_backup_vppTokens.py index cd3c47e0..46e93795 100644 --- a/tests/Backup/Intune/test_backup_vppTokens.py +++ b/tests/Backup/Intune/test_backup_vppTokens.py @@ -27,6 +27,19 @@ def setUp(self): self.vpp_token = { "value": [{"id": "0", "tokenName": "test", "displayName": "test"}] } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.patch_makeapirequest = patch( "src.IntuneCD.backup.Intune.backup_vppTokens.makeapirequest", @@ -34,15 +47,22 @@ def setUp(self): ) self.makeapirequest = self.patch_makeapirequest.start() + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_vppTokens.makeAuditRequest" + ) + self.get_scope_tags = self.makeAuditRequest_patch.start() + self.get_scope_tags.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.makeapirequest.stop() + self.makeAuditRequest_patch.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.token, self.append_id, False + self.directory.path, "yaml", self.token, self.append_id, False, "" ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -57,7 +77,7 @@ def test_backup_json(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.token, self.append_id, False + self.directory.path, "json", self.token, self.append_id, False, "" ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -72,14 +92,32 @@ def test_backup_with_no_return_data(self): self.makeapirequest.return_value = {"value": []} self.count = savebackup( - self.directory.path, "json", self.token, self.append_id, False + self.directory.path, "json", self.token, self.append_id, False, "" ) self.assertEqual(0, self.count["config_count"]) def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" - self.count = savebackup(self.directory.path, "json", self.token, True, False) + self.count = savebackup( + self.directory.path, "json", self.token, True, False, "" + ) + + self.assertTrue( + Path(f"{self.directory.path}/Apple VPP Tokens/test__0.json").exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.token, + True, + True, + [{"id": 0, "displayName": "default"}], + ) self.assertTrue( Path(f"{self.directory.path}/Apple VPP Tokens/test__0.json").exists() diff --git a/tests/Backup/Intune/test_backup_windowsDriverUpdates.py b/tests/Backup/Intune/test_backup_windowsDriverUpdates.py index 56c2ecda..c3dc24e1 100644 --- a/tests/Backup/Intune/test_backup_windowsDriverUpdates.py +++ b/tests/Backup/Intune/test_backup_windowsDriverUpdates.py @@ -32,6 +32,19 @@ def setUp(self): "displayName": "test", } self.enrollment_profile = {"value": [{"displayName": "test", "id": "0"}]} + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_windowsDriverUpdates.batch_assignment" @@ -51,11 +64,18 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.enrollment_profile + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_windowsDriverUpdates.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -69,6 +89,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -91,6 +112,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -112,6 +134,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -127,6 +150,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -134,7 +158,25 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None + ) + + self.assertTrue( + Path(f"{self.directory.path}/Driver Updates/test__0.json").exists() + ) + + def test_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_windowsEnrollmentProfile.py b/tests/Backup/Intune/test_backup_windowsEnrollmentProfile.py index 4bf6bd72..161aac4f 100644 --- a/tests/Backup/Intune/test_backup_windowsEnrollmentProfile.py +++ b/tests/Backup/Intune/test_backup_windowsEnrollmentProfile.py @@ -32,6 +32,19 @@ def setUp(self): "displayName": "test", } self.enrollment_profile = {"value": [{"displayName": "test", "id": "0"}]} + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_windowsEnrollmentProfile.batch_assignment" @@ -51,11 +64,18 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.enrollment_profile + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_windowsEnrollmentProfile.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -69,6 +89,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -91,6 +112,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -112,6 +134,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -127,6 +150,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -134,7 +158,27 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Enrollment Profiles/Windows/test__0.json" + ).exists() + ) + + def test_backup_scope_tags_and_aduit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_windowsFeatureUpdates.py b/tests/Backup/Intune/test_backup_windowsFeatureUpdates.py index a5b30e09..b6bf4dc2 100644 --- a/tests/Backup/Intune/test_backup_windowsFeatureUpdates.py +++ b/tests/Backup/Intune/test_backup_windowsFeatureUpdates.py @@ -32,6 +32,19 @@ def setUp(self): "displayName": "test", } self.enrollment_profile = {"value": [{"displayName": "test", "id": "0"}]} + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_windowsFeatureUpdates.batch_assignment" @@ -51,11 +64,18 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.enrollment_profile + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_windowsFeatureUpdates.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -69,6 +89,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -91,6 +112,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -112,6 +134,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -127,6 +150,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -134,7 +158,25 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None + ) + + self.assertTrue( + Path(f"{self.directory.path}/Feature Updates/test__0.json").exists() + ) + + def test_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_windowsQualityUpdates.py b/tests/Backup/Intune/test_backup_windowsQualityUpdates.py index e9ae7367..157331cc 100644 --- a/tests/Backup/Intune/test_backup_windowsQualityUpdates.py +++ b/tests/Backup/Intune/test_backup_windowsQualityUpdates.py @@ -32,6 +32,19 @@ def setUp(self): "displayName": "test", } self.enrollment_profile = {"value": [{"displayName": "test", "id": "0"}]} + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_windowsQualityUpdates.batch_assignment" @@ -51,11 +64,18 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.enrollment_profile + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_windowsQualityUpdates.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -69,6 +89,7 @@ def test_backup_yml(self): "", self.append_id, False, + None, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -91,6 +112,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + output, "r", encoding="utf-8") as f: @@ -112,6 +134,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -127,6 +150,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -134,7 +158,25 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "json", self.exclude, self.token, "", True, False + self.directory.path, "json", self.exclude, self.token, "", True, False, None + ) + + self.assertTrue( + Path(f"{self.directory.path}/Quality Updates/test__0.json").exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Update/Intune/test_update_ManagementIntents.py b/tests/Update/Intune/test_update_ManagementIntents.py index 4c163a52..d4dcbaef 100644 --- a/tests/Update/Intune/test_update_ManagementIntents.py +++ b/tests/Update/Intune/test_update_ManagementIntents.py @@ -231,6 +231,21 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPost.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_compliance.py b/tests/Update/Intune/test_update_compliance.py index 42cdba13..0115b1da 100644 --- a/tests/Update/Intune/test_update_compliance.py +++ b/tests/Update/Intune/test_update_compliance.py @@ -189,6 +189,21 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 2) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_customAttributeShellScript.py b/tests/Update/Intune/test_update_customAttributeShellScript.py index 949b9e6b..6f53492e 100644 --- a/tests/Update/Intune/test_update_customAttributeShellScript.py +++ b/tests/Update/Intune/test_update_customAttributeShellScript.py @@ -208,6 +208,25 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.mem_data["testvalue"] = "test" + self.mem_data["scriptContent"] = self.repo_script_content + + self.makeapirequest.side_effect = [self.mem_shellScript_data, self.mem_data] + + self.count = update( + self.directory.path, + self.token, + remove=False, + assignment=True, + scope_tags=["test"], + ) + + self.assertEqual(self.makeapirequestPatch.call_count, 0) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_deviceCategories.py b/tests/Update/Intune/test_update_deviceCategories.py index 8aae6fec..5d2b5b1d 100644 --- a/tests/Update/Intune/test_update_deviceCategories.py +++ b/tests/Update/Intune/test_update_deviceCategories.py @@ -78,7 +78,9 @@ def tearDown(self): def test_update_with_diffs(self): """The count should be 1 and makeapirequestPatch should be called.""" - self.count = update(self.directory.path, self.token, report=False, remove=False) + self.count = update( + self.directory.path, self.token, report=False, remove=False, scope_tags=[] + ) self.assertEqual(self.count[0].count, 1) self.assertEqual(self.makeapirequestPatch.call_count, 1) @@ -91,7 +93,9 @@ def test_update_with_multiple_diffs(self): self.mem_data["value"][0]["testvalue"] = "test" self.mem_data["value"][0]["testvalue2"] = "test1" - self.count = update(self.directory.path, self.token, report=False, remove=False) + self.count = update( + self.directory.path, self.token, report=False, remove=False, scope_tags=[] + ) self.assertEqual(self.count[0].count, 2) self.assertEqual(self.makeapirequestPatch.call_count, 1) @@ -101,7 +105,9 @@ def test_update_with_no_diffs(self): """The count should be 0 and makeapirequestPatch should not be called.""" self.mem_data["value"][0]["testvalue"] = "test1" - self.count = update(self.directory.path, self.token, report=False, remove=False) + self.count = update( + self.directory.path, self.token, report=False, remove=False, scope_tags=[] + ) self.assertEqual(self.count[0].count, 0) self.assertEqual(self.makeapirequestPatch.call_count, 0) @@ -111,7 +117,9 @@ def test_update_config_not_found(self): """The count should be 0 and makeapirequestPost should be called.""" self.mem_data["value"][0]["displayName"] = "test1" - self.count = update(self.directory.path, self.token, report=False, remove=False) + self.count = update( + self.directory.path, self.token, report=False, remove=False, scope_tags=[] + ) self.assertEqual(self.count, []) self.assertEqual(self.makeapirequestPost.call_count, 1) @@ -120,10 +128,26 @@ def test_update_config_remove(self): """The count should be 0 and makeapirequestPost should be called.""" os.remove(self.directory.path + "/Device Categories/test.json") - self.count = update(self.directory.path, self.token, report=False, remove=True) + self.count = update( + self.directory.path, self.token, report=False, remove=True, scope_tags=[] + ) self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + remove=False, + report=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_enrollmentStatusPage.py b/tests/Update/Intune/test_update_enrollmentStatusPage.py index a966f9f6..f4ea34fa 100644 --- a/tests/Update/Intune/test_update_enrollmentStatusPage.py +++ b/tests/Update/Intune/test_update_enrollmentStatusPage.py @@ -209,6 +209,21 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 2) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_notificationTemplate.py b/tests/Update/Intune/test_update_notificationTemplate.py index c5eaa52d..361a771f 100644 --- a/tests/Update/Intune/test_update_notificationTemplate.py +++ b/tests/Update/Intune/test_update_notificationTemplate.py @@ -36,7 +36,6 @@ def setUp(self): "displayName": "test", "defaultLocale": "en-us", "brandingOptions": "test", - "roleScopeTagIds": "[0]", "localizedNotificationMessages": [{"messageTemplate": "test"}], } ] @@ -46,7 +45,7 @@ def setUp(self): "displayName": "test", "defaultLocale": "en-us", "brandingOptions": "test", - "roleScopeTagIds": "[0]", + "roleScopeTagIds": [], "localizedNotificationMessages": [ { "messageTemplate": "test", @@ -60,7 +59,7 @@ def setUp(self): "displayName": "test", "defaultLocale": "en-us", "brandingOptions": "test", - "roleScopeTagIds": "[0]", + "roleScopeTagIds": [], "localizedNotificationMessages": [ {"messageTemplate": "test1", "locale": "en-us"} ], @@ -106,11 +105,12 @@ def test_update_with_diffs(self): """The count should be 1 and makeapirequestPatch should be called.""" self.makeapirequest.side_effect = [self.mem_data, self.mem_template_data] - self.count = update(self.directory.path, self.token, report=False, remove=False) + self.count = update( + self.directory.path, self.token, report=False, remove=False, scope_tags=[] + ) self.assertEqual(self.count[0].count, 1) self.assertEqual(self.makeapirequestPatch.call_count, 1) - self.assertEqual(self.makeapirequestPatch.call_count, 1) def test_update_with_multiple_diffs(self): """The count should be 2 and makeapirequestPatch should be called.""" @@ -118,7 +118,9 @@ def test_update_with_multiple_diffs(self): self.repo_data["brandingOptions"] = "test1" self.makeapirequest.side_effect = [self.mem_data, self.mem_template_data] - self.count = update(self.directory.path, self.token, report=False, remove=False) + self.count = update( + self.directory.path, self.token, report=False, remove=False, scope_tags=[] + ) self.assertEqual(self.count[0].count, 2) self.assertEqual(self.makeapirequestPatch.call_count, 2) @@ -130,7 +132,9 @@ def test_update_with_no_diffs(self): "messageTemplate" ] = "test1" self.makeapirequest.side_effect = [self.mem_data, self.mem_template_data] - self.count = update(self.directory.path, self.token, report=False, remove=False) + self.count = update( + self.directory.path, self.token, report=False, remove=False, scope_tags=[] + ) self.assertEqual(self.count[0].count, 0) self.assertEqual(self.makeapirequestPatch.call_count, 0) @@ -139,7 +143,9 @@ def test_update_config_not_found(self): """The count should be 0 and makeapirequestPost should be called.""" self.mem_data["value"][0]["displayName"] = "test1" - self.count = update(self.directory.path, self.token, report=False, remove=False) + self.count = update( + self.directory.path, self.token, report=False, remove=False, scope_tags=[] + ) self.assertEqual(self.count, []) self.assertEqual(self.makeapirequestPost.call_count, 2) @@ -157,10 +163,28 @@ def test_remove_config(self): self.makeapirequest.side_effect = [self.mem_data, self.mem_template_data] - self.update = update(self.directory.path, self.token, report=False, remove=True) + self.update = update( + self.directory.path, self.token, report=False, remove=True, scope_tags=[] + ) self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.makeapirequest.side_effect = [self.mem_data, self.mem_template_data] + + self.count = update( + self.directory.path, + self.token, + remove=False, + report=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_powershellScripts.py b/tests/Update/Intune/test_update_powershellScripts.py index a6533e4a..19720d01 100644 --- a/tests/Update/Intune/test_update_powershellScripts.py +++ b/tests/Update/Intune/test_update_powershellScripts.py @@ -230,6 +230,26 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.makeapirequest.side_effect = [ + self.mem_powershellScript_data, + self.mem_data, + ] + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_proactiveRemediation.py b/tests/Update/Intune/test_update_proactiveRemediation.py index 383fa64a..14501ffb 100644 --- a/tests/Update/Intune/test_update_proactiveRemediation.py +++ b/tests/Update/Intune/test_update_proactiveRemediation.py @@ -319,6 +319,27 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["testvalue"] = "test" + self.makeapirequest.side_effect = [ + self.mem_remediationScript_data, + self.mem_data, + ] + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 0) + self.assertEqual(self.makeapirequestPatch.call_count, 0) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_profiles.py b/tests/Update/Intune/test_update_profiles.py index 829ad627..8e2a4cc3 100644 --- a/tests/Update/Intune/test_update_profiles.py +++ b/tests/Update/Intune/test_update_profiles.py @@ -738,6 +738,21 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_roles.py b/tests/Update/Intune/test_update_roles.py index 95f5a8aa..4b0928aa 100644 --- a/tests/Update/Intune/test_update_roles.py +++ b/tests/Update/Intune/test_update_roles.py @@ -50,7 +50,6 @@ def setUp(self): "description": "", "isBuiltInRoleDefinition": False, "isBuiltIn": False, - "roleScopeTagIds": ["0"], "rolePermissions": [ { "resourceActions": [ @@ -166,6 +165,20 @@ def test_update_config_not_found_remove(self): # self.assertEqual(self.count, []) self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + remove=False, + report=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 0) + self.assertEqual(self.makeapirequestPatch.call_count, 0) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_shellScripts.py b/tests/Update/Intune/test_update_shellScripts.py index 04933482..c87e57b5 100644 --- a/tests/Update/Intune/test_update_shellScripts.py +++ b/tests/Update/Intune/test_update_shellScripts.py @@ -215,6 +215,24 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["testvalue"] = "test1" + self.makeapirequest.side_effect = [self.mem_shellScript_data, self.mem_data] + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 2) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_windowsDriverUpdates.py b/tests/Update/Intune/test_update_windowsDriverUpdates.py index ae761b1e..8c82839d 100644 --- a/tests/Update/Intune/test_update_windowsDriverUpdates.py +++ b/tests/Update/Intune/test_update_windowsDriverUpdates.py @@ -184,6 +184,21 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_windowsEnrollmentProfile.py b/tests/Update/Intune/test_update_windowsEnrollmentProfile.py index f0580e01..254b8d03 100644 --- a/tests/Update/Intune/test_update_windowsEnrollmentProfile.py +++ b/tests/Update/Intune/test_update_windowsEnrollmentProfile.py @@ -184,6 +184,21 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 2) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_windowsFeatureUpdates.py b/tests/Update/Intune/test_update_windowsFeatureUpdates.py index 76586a36..e1bfdc34 100644 --- a/tests/Update/Intune/test_update_windowsFeatureUpdates.py +++ b/tests/Update/Intune/test_update_windowsFeatureUpdates.py @@ -185,6 +185,21 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_windowsQualityUpdates.py b/tests/Update/Intune/test_update_windowsQualityUpdates.py index 1d36ee79..e2e21702 100644 --- a/tests/Update/Intune/test_update_windowsQualityUpdates.py +++ b/tests/Update/Intune/test_update_windowsQualityUpdates.py @@ -185,6 +185,21 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() From 24d4e3a50b22271efe32199b1ae556cc3f894271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:01:07 +0100 Subject: [PATCH 08/35] add processing of scope tags --- tests/Backup/Intune/test_backup_apns.py | 39 +++++++++++++++ .../Intune/test_backup_appConfiguration.py | 49 ++++++++++++++++++- .../test_backup_appleEnrollmentProfile.py | 39 +++++++++++++++ .../Intune/test_backup_compliancePartner.py | 39 +++++++++++++++ .../test_backup_deviceManagementSettings.py | 40 +++++++++++++++ .../Backup/Intune/test_backup_managedGPlay.py | 39 +++++++++++++++ .../Intune/test_backup_managementPartner.py | 37 ++++++++++++++ .../test_backup_remoteAssistancePartner.py | 37 ++++++++++++++ tests/Backup/Intune/test_backup_scopeTags.py | 35 +++++++++++++ .../Intune/test_update_appConfiguration.py | 15 ++++++ .../Intune/test_update_appProtection.py | 15 ++++++ .../Intune/test_update_assignmentFilter.py | 29 +++++++++-- .../test_update_configurationPolicies.py | 13 +++++ .../test_update_enrollmentConfigurations.py | 15 ++++++ .../test_update_groupPolicyConfiguration.py | 15 ++++++ 15 files changed, 451 insertions(+), 5 deletions(-) diff --git a/tests/Backup/Intune/test_backup_apns.py b/tests/Backup/Intune/test_backup_apns.py index e2706476..4bae8adf 100644 --- a/tests/Backup/Intune/test_backup_apns.py +++ b/tests/Backup/Intune/test_backup_apns.py @@ -44,15 +44,41 @@ def setUp(self): "certificateSerialNumber": "11000000000000", "certificate": None, } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.makeapirequest_patch = patch( "src.IntuneCD.backup.Intune.backup_apns.makeapirequest" ) self.makeapirequest = self.makeapirequest_patch.start() + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_apns.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + + self.process_audit_data_patch = patch( + "src.IntuneCD.backup.Intune.backup_apns.process_audit_data" + ) + self.process_audit_data = self.process_audit_data_patch.start() + def tearDown(self): self.directory.cleanup() self.makeapirequest_patch.stop() + self.makeAuditRequest_patch.stop() + self.process_audit_data_patch.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -88,6 +114,19 @@ def test_backup_with_no_return_data(self): self.count = savebackup(self.directory.path, "json", False, self.token) self.assertEqual(0, self.count["config_count"]) + def test_backup_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.makeapirequest.return_value = self.apns + self.count = savebackup(self.directory.path, "json", True, self.token) + + with open(self.saved_path + "json", "r", encoding="utf-8") as f: + saved_data = json.load(f) + + self.assertTrue(Path(f"{self.directory.path}/Apple Push Notification").exists()) + self.assertEqual(self.expected_data, saved_data) + self.assertEqual(1, self.count["config_count"]) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_appConfiguration.py b/tests/Backup/Intune/test_backup_appConfiguration.py index 768d03b8..8d5abac3 100644 --- a/tests/Backup/Intune/test_backup_appConfiguration.py +++ b/tests/Backup/Intune/test_backup_appConfiguration.py @@ -33,6 +33,7 @@ def setUp(self): "@odata.type": "#microsoft.graph.iosMobileAppConfiguration", "assignments": [{"target": {"groupName": "Group1"}}], "displayName": "test", + "scopeTagIds": ["0"], "settings": [ { "appConfigKey": "sharedDevice", @@ -54,6 +55,7 @@ def setUp(self): "id": "0", "targetedMobileApps": ["0"], "displayName": "test", + "scopeTagIds": ["0"], "settings": [ { "appConfigKey": "sharedDevice", @@ -74,6 +76,19 @@ def setUp(self): "applicableDeviceType": {"iPhoneAndIPod": True}, "revokeLicenseActionResults": [], } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_appConfiguration.batch_assignment" @@ -93,11 +108,18 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.side_effect = self.app_config, self.app_data + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_appConfiguration.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -110,6 +132,7 @@ def test_backup_yml(self): "", self.append_id, False, + [{"id": 0, "displayName": "default"}], ) with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: @@ -131,6 +154,7 @@ def test_backup_json(self): "", self.append_id, False, + None, ) with open(self.saved_path + "json", "r", encoding="utf-8") as f: @@ -151,6 +175,7 @@ def test_backup_with_no_returned_data(self): "", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -165,6 +190,7 @@ def test_backup_with_prefix(self): "test1", self.append_id, False, + None, ) self.assertEqual(0, self.count["config_count"]) @@ -173,7 +199,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.count = savebackup( - self.directory.path, "yaml", self.exclude, self.token, "", True, False + self.directory.path, "yaml", self.exclude, self.token, "", True, False, None ) self.assertTrue( @@ -182,6 +208,27 @@ def test_backup_append_id(self): ).exists() ) + def test_backup_scope_tag_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + self.count = savebackup( + self.directory.path, + "yaml", + self.exclude, + self.token, + "", + self.append_id, + True, + [{"id": 0, "displayName": "default"}], + ) + + with open(self.saved_path + "yaml", "r", encoding="utf-8") as f: + data = json.dumps(yaml.safe_load(f)) + saved_data = json.loads(data) + + self.assertTrue(Path(f"{self.directory.path}/App Configuration").exists()) + self.assertEqual(self.expected_data, saved_data) + self.assertEqual(1, self.count["config_count"]) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_appleEnrollmentProfile.py b/tests/Backup/Intune/test_backup_appleEnrollmentProfile.py index 17efeea3..0c524350 100644 --- a/tests/Backup/Intune/test_backup_appleEnrollmentProfile.py +++ b/tests/Backup/Intune/test_backup_appleEnrollmentProfile.py @@ -62,6 +62,19 @@ def setUp(self): ] } ] + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.patch_makeapirequest = patch( "src.IntuneCD.backup.Intune.backup_appleEnrollmentProfile.makeapirequest" @@ -73,10 +86,23 @@ def setUp(self): ) self.batch_request = self.patch_batch_request.start() + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_appleEnrollmentProfile.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + + self.process_audit_data_patch = patch( + "src.IntuneCD.backup.Intune.backup_appleEnrollmentProfile.process_audit_data" + ) + self.process_audit_data = self.process_audit_data_patch.start() + def tearDown(self): self.directory.cleanup() self.patch_batch_request.stop() self.patch_makeapirequest.stop() + self.makeAuditRequest_patch.stop() + self.process_audit_data_patch.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -149,6 +175,19 @@ def test_backup_append_id(self): ).exists() ) + def test_backup_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + self.makeapirequest.return_value = self.token_response + self.batch_request.return_value = self.batch_intune + + self.count = savebackup(self.directory.path, "json", self.token, "", True, True) + + self.assertTrue( + Path( + f"{self.directory.path}/Enrollment Profiles/Apple/test__0.json" + ).exists() + ) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_compliancePartner.py b/tests/Backup/Intune/test_backup_compliancePartner.py index 16a487ed..b7f98f70 100644 --- a/tests/Backup/Intune/test_backup_compliancePartner.py +++ b/tests/Backup/Intune/test_backup_compliancePartner.py @@ -55,6 +55,19 @@ def setUp(self): } ] } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.patch_makeapirequest = patch( "src.IntuneCD.backup.Intune.backup_compliancePartner.makeapirequest", @@ -62,9 +75,22 @@ def setUp(self): ) self.makeapirequest = self.patch_makeapirequest.start() + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_compliancePartner.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + + self.process_audit_data_patch = patch( + "src.IntuneCD.backup.Intune.backup_compliancePartner.process_audit_data" + ) + self.process_audit_data = self.process_audit_data_patch.start() + def tearDown(self): self.directory.cleanup() self.makeapirequest.stop() + self.makeAuditRequest_patch.stop() + self.process_audit_data_patch.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -135,6 +161,19 @@ def test_backup_exclude_lastHeartbeatDateTime(self): self.assertNotIn("lastHeartbeatDateTime", saved_data) + def test_backup_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, "json", self.exclude, self.token, True, True + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Partner Connections/Compliance/test__0.json" + ).exists() + ) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_deviceManagementSettings.py b/tests/Backup/Intune/test_backup_deviceManagementSettings.py index 7086fdfb..93e2e0d1 100644 --- a/tests/Backup/Intune/test_backup_deviceManagementSettings.py +++ b/tests/Backup/Intune/test_backup_deviceManagementSettings.py @@ -58,9 +58,35 @@ def setUp(self): "enableEnhancedTroubleshootingExperience": False, "enableDeviceGroupMembershipReport": False, } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } + + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_deviceManagementSettings.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + + self.process_audit_data_patch = patch( + "src.IntuneCD.backup.Intune.backup_deviceManagementSettings.process_audit_data" + ) + self.process_audit_data = self.process_audit_data_patch.start() def tearDown(self): self.directory.cleanup() + self.makeAuditRequest_patch.stop() + self.process_audit_data_patch.stop() def test_backup_yml(self, _, __): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -91,6 +117,20 @@ def test_backup_json(self, _, __): self.assertEqual(self.expected_data, self.saved_data) self.assertEqual(1, self.count["config_count"]) + def test_backup_audit(self, _, __): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup(self.directory.path, "json", True, self.token) + + with open(self.saved_path + "json", "r", encoding="utf-8") as f: + self.saved_data = json.load(f) + + self.assertTrue( + Path(f"{self.directory.path}/Device Management Settings").exists() + ) + self.assertEqual(self.expected_data, self.saved_data) + self.assertEqual(1, self.count["config_count"]) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_managedGPlay.py b/tests/Backup/Intune/test_backup_managedGPlay.py index 9223fcb1..cfdc5ba8 100644 --- a/tests/Backup/Intune/test_backup_managedGPlay.py +++ b/tests/Backup/Intune/test_backup_managedGPlay.py @@ -39,6 +39,19 @@ def setUp(self): "lastAppSyncStatus": "success", "ownerUserPrincipalName": "awesome@gmail.com", } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.patch_makeapirequest = patch( "src.IntuneCD.backup.Intune.backup_managedGPlay.makeapirequest", @@ -46,9 +59,22 @@ def setUp(self): ) self.makeapirequest = self.patch_makeapirequest.start() + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_managedGPlay.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + + self.process_audit_data_patch = patch( + "src.IntuneCD.backup.Intune.backup_managedGPlay.process_audit_data" + ) + self.process_audit_data = self.process_audit_data_patch.start() + def tearDown(self): self.directory.cleanup() self.makeapirequest.stop() + self.makeAuditRequest_patch.stop() + self.process_audit_data_patch.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -114,6 +140,19 @@ def test_backup_exclude_lastAppSyncDateTime(self): self.assertNotIn("lastAppSyncDateTime", saved_data) + def test_backup_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, "json", self.exclude, self.token, True, True + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Managed Google Play/awesome@gmail.com__0.json" + ).exists() + ) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_managementPartner.py b/tests/Backup/Intune/test_backup_managementPartner.py index d4a537ff..62b59fbc 100644 --- a/tests/Backup/Intune/test_backup_managementPartner.py +++ b/tests/Backup/Intune/test_backup_managementPartner.py @@ -38,6 +38,19 @@ def setUp(self): } ] } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.patch_makeapirequest = patch( "src.IntuneCD.backup.Intune.backup_managementPartner.makeapirequest", @@ -45,9 +58,22 @@ def setUp(self): ) self.makeapirequest = self.patch_makeapirequest.start() + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_managementPartner.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + + self.process_audit_data_patch = patch( + "src.IntuneCD.backup.Intune.backup_managementPartner.process_audit_data" + ) + self.process_audit_data = self.process_audit_data_patch.start() + def tearDown(self): self.directory.cleanup() self.makeapirequest.stop() + self.makeAuditRequest_patch.stop() + self.process_audit_data_patch.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -102,6 +128,17 @@ def test_backup_append_id(self): ).exists() ) + def test_backup_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup(self.directory.path, "json", self.token, True, True) + + self.assertTrue( + Path( + f"{self.directory.path}/Partner Connections/Management/test__0.json" + ).exists() + ) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_remoteAssistancePartner.py b/tests/Backup/Intune/test_backup_remoteAssistancePartner.py index cca81796..2a92c45a 100644 --- a/tests/Backup/Intune/test_backup_remoteAssistancePartner.py +++ b/tests/Backup/Intune/test_backup_remoteAssistancePartner.py @@ -31,6 +31,19 @@ def setUp(self): {"id": "0", "onboardingStatus": "onboarded", "displayName": "test"} ] } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.patch_makeapirequest = patch( "src.IntuneCD.backup.Intune.backup_remoteAssistancePartner.makeapirequest", @@ -38,9 +51,22 @@ def setUp(self): ) self.makeapirequest = self.patch_makeapirequest.start() + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_remoteAssistancePartner.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + + self.process_audit_data_patch = patch( + "src.IntuneCD.backup.Intune.backup_remoteAssistancePartner.process_audit_data" + ) + self.process_audit_data = self.process_audit_data_patch.start() + def tearDown(self): self.directory.cleanup() self.makeapirequest.stop() + self.makeAuditRequest_patch.stop() + self.process_audit_data_patch.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -110,6 +136,17 @@ def test_backup_append_id(self): ).exists() ) + def test_backup_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup(self.directory.path, "json", self.token, True, True) + + self.assertTrue( + Path( + f"{self.directory.path}/Partner Connections/Remote Assistance/test__0.json" + ).exists() + ) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_scopeTags.py b/tests/Backup/Intune/test_backup_scopeTags.py index 846e398f..5d1433f7 100644 --- a/tests/Backup/Intune/test_backup_scopeTags.py +++ b/tests/Backup/Intune/test_backup_scopeTags.py @@ -44,6 +44,19 @@ def setUp(self): } ], } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_scopeTags.batch_assignment" @@ -63,11 +76,24 @@ def setUp(self): self.makeapirequest = self.makeapirequest_patch.start() self.makeapirequest.return_value = self.scope_tag + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_scopeTags.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + + self.process_audit_data_patch = patch( + "src.IntuneCD.backup.Intune.backup_scopeTags.process_audit_data" + ) + self.process_audit_data = self.process_audit_data_patch.start() + def tearDown(self): self.directory.cleanup() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() + self.makeAuditRequest.stop() + self.process_audit_data.stop() def test_backup_yml(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" @@ -116,6 +142,15 @@ def test_backup_append_id(self): self.assertTrue(Path(f"{self.directory.path}/Scope Tags/test__1.json").exists()) + def test_backup_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, "json", self.exclude, self.token, True, True + ) + + self.assertTrue(Path(f"{self.directory.path}/Scope Tags/test__1.json").exists()) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_appConfiguration.py b/tests/Update/Intune/test_update_appConfiguration.py index bcd39f15..afdb35a9 100644 --- a/tests/Update/Intune/test_update_appConfiguration.py +++ b/tests/Update/Intune/test_update_appConfiguration.py @@ -188,6 +188,21 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_appProtection.py b/tests/Update/Intune/test_update_appProtection.py index df55f16e..0b41cf45 100644 --- a/tests/Update/Intune/test_update_appProtection.py +++ b/tests/Update/Intune/test_update_appProtection.py @@ -466,6 +466,21 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_assignmentFilter.py b/tests/Update/Intune/test_update_assignmentFilter.py index f1c5a777..ab4a0c87 100644 --- a/tests/Update/Intune/test_update_assignmentFilter.py +++ b/tests/Update/Intune/test_update_assignmentFilter.py @@ -67,7 +67,9 @@ def tearDown(self): def test_update_with_diffs(self): """The count should be 1 and makeapirequestPatch should be called.""" - self.count = update(self.directory.path, self.token, report=False) + self.count = update( + self.directory.path, self.token, report=False, scope_tags=[] + ) self.assertEqual(self.count[0].count, 1) self.assertEqual(self.makeapirequestPatch.call_count, 1) @@ -80,7 +82,9 @@ def test_update_with_multiple_diffs(self): self.mem_data["value"][0]["testvalue"] = "test" self.mem_data["value"][0]["testvalue2"] = "test1" - self.count = update(self.directory.path, self.token, report=False) + self.count = update( + self.directory.path, self.token, report=False, scope_tags=[] + ) self.assertEqual(self.count[0].count, 2) self.assertEqual(self.makeapirequestPatch.call_count, 1) @@ -90,7 +94,9 @@ def test_update_with_no_diffs(self): """The count should be 0 and makeapirequestPatch should not be called.""" self.mem_data["value"][0]["testvalue"] = "test1" - self.count = update(self.directory.path, self.token, report=False) + self.count = update( + self.directory.path, self.token, report=False, scope_tags=[] + ) self.assertEqual(self.count[0].count, 0) self.assertEqual(self.makeapirequestPatch.call_count, 0) @@ -100,11 +106,26 @@ def test_update_config_not_found(self): """The count should be 0 and makeapirequestPost should be called.""" self.mem_data["value"][0]["displayName"] = "test1" - self.count = update(self.directory.path, self.token, report=False) + self.count = update( + self.directory.path, self.token, report=False, scope_tags=[] + ) self.assertEqual(self.count, []) self.assertEqual(self.makeapirequestPost.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + report=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_configurationPolicies.py b/tests/Update/Intune/test_update_configurationPolicies.py index 59fa29c3..3376d563 100644 --- a/tests/Update/Intune/test_update_configurationPolicies.py +++ b/tests/Update/Intune/test_update_configurationPolicies.py @@ -200,6 +200,19 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_enrollmentConfigurations.py b/tests/Update/Intune/test_update_enrollmentConfigurations.py index ce98e59d..5726474a 100644 --- a/tests/Update/Intune/test_update_enrollmentConfigurations.py +++ b/tests/Update/Intune/test_update_enrollmentConfigurations.py @@ -226,6 +226,21 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_groupPolicyConfiguration.py b/tests/Update/Intune/test_update_groupPolicyConfiguration.py index 5a2a651f..3bd8819e 100644 --- a/tests/Update/Intune/test_update_groupPolicyConfiguration.py +++ b/tests/Update/Intune/test_update_groupPolicyConfiguration.py @@ -441,6 +441,21 @@ def test_remove_config(self): self.assertEqual(self.makeapirequestDelete.call_count, 1) + def test_update_scope_tags(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, + self.token, + assignment=True, + remove=False, + scope_tags=[{"displayName": "test"}], + ) + + self.assertEqual(self.count[0].count, 3) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + if __name__ == "__main__": unittest.main() From 281ce1d89de8e8b224d4f5d29f1b2dd1dcb2e49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:17:46 +0100 Subject: [PATCH 09/35] set audit_days_back via env and logging --- src/IntuneCD/intunecdlib/graph_request.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/IntuneCD/intunecdlib/graph_request.py b/src/IntuneCD/intunecdlib/graph_request.py index ce3e7ebc..b32f81ad 100644 --- a/src/IntuneCD/intunecdlib/graph_request.py +++ b/src/IntuneCD/intunecdlib/graph_request.py @@ -7,10 +7,12 @@ import datetime import json +import os import time - import requests +from .logger import log + def makeapirequest(endpoint, token, q_param=None): """ @@ -248,11 +250,18 @@ def makeAuditRequest(graph_filter, token): """ audit_data = [] + if not os.getenv("AUDIT_DAYS_BACK"): + days_back = 1 + else: + days_back = int(os.getenv("AUDIT_DAYS_BACK")) + log("makeAuditRequest", f"AUDIT_DAYS_BACK: {days_back}") # Get the date and time 24 hours ago and format it - start_date = datetime.datetime.now() - datetime.timedelta(days=1) + start_date = datetime.datetime.now() - datetime.timedelta(days=days_back) start_date = start_date.strftime("%Y-%m-%dT%H:%M:%S.%fZ") + log("makeAuditRequest", f"Start date: {start_date}") # Get the current date and time end_date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ") + log("makeAuditRequest", f"End date: {end_date}") # Create query to get audit logs for the object # if not graph_filter: # graph_filter = f"resources/any(s:s/resourceId eq '{pid}')" @@ -264,6 +273,7 @@ def makeAuditRequest(graph_filter, token): "$select": "actor,activityDateTime,activityOperationType,activityResult,resources", "$orderby": "activityDateTime desc", } + log("makeAuditRequest", f"Query parameters: {q_param}") # Make the request to the Microsoft Graph API endpoint = "https://graph.microsoft.com/v1.0/deviceManagement/auditEvents" @@ -271,12 +281,14 @@ def makeAuditRequest(graph_filter, token): # If there are audit logs, return the latest one if data["value"]: + log("makeAuditRequest", f"Got {len(data['value'])} audit logs.") for audit_log in data["value"]: # is the actor an app or a user? if audit_log["actor"]["auditActorType"] == "ItPro": actor = audit_log["actor"].get("userPrincipalName") else: actor = audit_log["actor"].get("applicationDisplayName") + log("makeAuditRequest", f"Actor found: {actor}") audit_data.append( { "resourceId": audit_log["resources"][0]["resourceId"], From c2d20f457f3f41d93f213884b2066dd959a5e608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:18:07 +0100 Subject: [PATCH 10/35] clean up commit message --- src/IntuneCD/intunecdlib/process_audit_data.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/IntuneCD/intunecdlib/process_audit_data.py b/src/IntuneCD/intunecdlib/process_audit_data.py index bcdab1b2..a7030f2b 100644 --- a/src/IntuneCD/intunecdlib/process_audit_data.py +++ b/src/IntuneCD/intunecdlib/process_audit_data.py @@ -147,8 +147,9 @@ def _git_commit_changes(audit_record, path, file): "commit", "-m", ( - f"Updated by {audit_record['actor']} on {audit_record['activityDateTime']}, " - f"change type: {audit_record['activityOperationType']}, result: {audit_record['activityResult']}" + f"{audit_record['activityOperationType']} by {audit_record['actor']}\n" + f"Date: {audit_record['activityDateTime']}\n" + f"result: {audit_record['activityResult']}" ), ] From 640863621a53f58bc5054d3ae06f0e473b1aa5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:18:21 +0100 Subject: [PATCH 11/35] look for additional keys --- .../intunecdlib/process_scope_tags.py | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/IntuneCD/intunecdlib/process_scope_tags.py b/src/IntuneCD/intunecdlib/process_scope_tags.py index bc248c55..b6ab929d 100644 --- a/src/IntuneCD/intunecdlib/process_scope_tags.py +++ b/src/IntuneCD/intunecdlib/process_scope_tags.py @@ -28,16 +28,20 @@ def get_scope_tags_name(data, scope_tags): :param scope_tags: The scope tag to search for """ - log("get_scope_tags_name", "Checking if scope tags are in the data.") - if data.get("roleScopeTagIds"): - log("get_scope_tags_name", "Scope tags are in the data.") + def _get_scope_tags(scope_tag_key): + log("get_scope_tags_name", "Checking if scope tags are in the data.") # list comprehension to get the scope tag name - data["roleScopeTagIds"] = [ - tag["displayName"] - for tag in scope_tags - if tag["id"] in data["roleScopeTagIds"] - ] - log("get_scope_tags_name", f"Scope tags: {data['roleScopeTagIds']}") + if data.get(scope_tag_key): + log("get_scope_tags_name", "Scope tags are in the data.") + data[scope_tag_key] = [ + tag["displayName"] + for tag in scope_tags + if tag["id"] in data[scope_tag_key] + ] + log("get_scope_tags_name", f"Scope tags: {data[scope_tag_key]}") + + _get_scope_tags("roleScopeTagIds") + _get_scope_tags("roleScopeTags") return data @@ -50,15 +54,19 @@ def get_scope_tags_id(data, scope_tags): :param scope_tags: The scope tag to search for """ - log("get_scope_tags_id", "Checking if scope tags are in the data.") - if data.get("roleScopeTagIds"): - log("get_scope_tags_id", "Scope tags are in the data.") - # list comprehension to get the scope tag ID - data["roleScopeTagIds"] = [ - tag["id"] - for tag in scope_tags - if tag["displayName"] in data["roleScopeTagIds"] - ] - log("get_scope_tags_id", f"Scope tags: {data['roleScopeTagIds']}") + def _get_scope_tags(scope_tag_key): + log("get_scope_tags_id", "Checking if scope tags are in the data.") + # list comprehension to get the scope tag name + if data.get(scope_tag_key): + log("get_scope_tags_id", "Scope tags are in the data.") + data[scope_tag_key] = [ + tag["id"] + for tag in scope_tags + if tag["displayName"] in data[scope_tag_key] + ] + log("get_scope_tags_id", f"Scope tags: {data[scope_tag_key]}") + + _get_scope_tags("roleScopeTagIds") + _get_scope_tags("roleScopeTags") return data From 034ac9ea59731d57f6c996589762aed87a249804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:18:39 +0100 Subject: [PATCH 12/35] batch get scope tags for apps --- src/IntuneCD/backup/Intune/backup_applications.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/IntuneCD/backup/Intune/backup_applications.py b/src/IntuneCD/backup/Intune/backup_applications.py index aa6c497d..88ad4dc4 100644 --- a/src/IntuneCD/backup/Intune/backup_applications.py +++ b/src/IntuneCD/backup/Intune/backup_applications.py @@ -8,7 +8,11 @@ import re from ...intunecdlib.clean_filename import clean_filename -from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment +from ...intunecdlib.graph_batch import ( + batch_assignment, + get_object_assignment, + batch_request, +) from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data from ...intunecdlib.process_scope_tags import get_scope_tags_name @@ -55,6 +59,11 @@ def savebackup(path, output, exclude, token, append_id, audit, scope_tags): assignment_responses = batch_assignment( data, "deviceAppManagement/mobileApps/", "/assignments", token ) + app_ids = [app["id"] for app in data["value"]] + scope_tag_responses = batch_request( + app_ids, "deviceAppManagement/mobileApps/", "?$select=roleScopeTagIds,id", token + ) + if audit: graph_filter = "componentName eq 'MobileApp'" audit_data = makeAuditRequest(graph_filter, token) @@ -64,6 +73,10 @@ def savebackup(path, output, exclude, token, append_id, audit, scope_tags): platform = "" results["config_count"] += 1 + scope_tag_data = [v for v in scope_tag_responses if app["id"] == v["id"]] + if scope_tag_data: + app["roleScopeTagIds"] = scope_tag_data[0]["roleScopeTagIds"] + if scope_tags: app = get_scope_tags_name(app, scope_tags) From c61b5af692aabdf4b3e6ac828230b477c033d51b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:18:53 +0100 Subject: [PATCH 13/35] batch get scope tags for apps --- .../Backup/Intune/test_backup_applications.py | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/tests/Backup/Intune/test_backup_applications.py b/tests/Backup/Intune/test_backup_applications.py index 75a5a9ca..631d10ba 100644 --- a/tests/Backup/Intune/test_backup_applications.py +++ b/tests/Backup/Intune/test_backup_applications.py @@ -23,6 +23,7 @@ def setUp(self): self.token = "token" self.exclude = [] self.append_id = False + self.scope_tag = {"roleScopeTagIds": ["0"]} self.app_base_data = { "value": [ { @@ -30,6 +31,7 @@ def setUp(self): "id": "0", "displayName": "test", "vppTokenAppleId": "test@test.com", + "roleScopeTagIds": ["0"], } ] } @@ -45,6 +47,12 @@ def setUp(self): ] } ] + self.batch_request_data = [ + { + "id": "0", + "roleScopeTagIds": ["0"], + } + ] self.object_assignment_data = [{"target": {"groupName": "Group1"}}] self.audit_data = { "value": [ @@ -60,6 +68,12 @@ def setUp(self): ] } + self.batch_request_patch = patch( + "src.IntuneCD.backup.Intune.backup_applications.batch_request" + ) + self.batch_request = self.batch_request_patch.start() + self.batch_request.return_value = self.batch_request_data + self.batch_assignment_patch = patch( "src.IntuneCD.backup.Intune.backup_applications.batch_assignment" ) @@ -85,6 +99,7 @@ def setUp(self): def tearDown(self): self.directory.cleanup() + self.batch_request_patch.stop() self.batch_assignment.stop() self.object_assignment.stop() self.makeapirequest.stop() @@ -94,7 +109,7 @@ def test_backup_ios_vpp_app(self): """The folder should be created, the file should be created, and the count should be 1.""" self.app_base_data["value"][0]["@odata.type"] = "#microsoft.graph.iosVppApp" - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.count = savebackup( self.directory.path, @@ -118,7 +133,7 @@ def test_backup_macOS_vpp_app(self): """The folder should be created, the file should be created, and the count should be 1.""" self.app_base_data["value"][0]["@odata.type"] = "#microsoft.graph.macOsVppApp" - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.count = savebackup( self.directory.path, @@ -144,7 +159,7 @@ def test_backup_vpp_app_exclude_licensecount(self): self.app_base_data["value"][0]["@odata.type"] = "#microsoft.graph.iosVppApp" self.app_base_data["value"][0]["usedLicenseCount"] = "1" - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.exclude = ["VPPusedLicenseCount"] @@ -172,7 +187,7 @@ def test_backup_win32_lob_app_and_displayVersion(self): self.app_base_data["value"][0]["@odata.type"] = "#microsoft.graph.win32LobApp" self.app_base_data["value"][0]["displayVersion"] = "1.0.0" - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.count = savebackup( self.directory.path, @@ -197,7 +212,7 @@ def test_backup_win32_lob_app_no_displayVersion(self): self.app_base_data["value"][0]["@odata.type"] = "#microsoft.graph.win32LobApp" self.app_base_data["value"][0]["displayVersion"] = None - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.count = savebackup( self.directory.path, @@ -222,7 +237,7 @@ def test_backup_msi_app(self): "@odata.type" ] = "#microsoft.graph.windowsMobileMSI" self.app_base_data["value"][0]["productVersion"] = "1.0.0" - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.count = savebackup( self.directory.path, @@ -248,7 +263,7 @@ def test_backup_android_app(self): self.app_base_data["value"][0][ "@odata.type" ] = "#microsoft.graph.androidManagedStoreApp" - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.count = savebackup( self.directory.path, @@ -273,7 +288,7 @@ def test_backup_microsoft_app(self): """The folder should be created, the file should be created, and the count should be 1.""" self.app_base_data["value"][0]["@odata.type"] = "#microsoft.graph.microsoftApp" - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.count = savebackup( self.directory.path, @@ -299,7 +314,7 @@ def test_backup_office_suite_app(self): self.app_base_data["value"][0][ "@odata.type" ] = "#microsoft.graph.microsoftOfficeSuiteApp" - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.count = savebackup( self.directory.path, @@ -326,7 +341,7 @@ def test_backup_web_app(self): """The folder should be created, the file should be created, and the count should be 1.""" self.app_base_data["value"][0]["@odata.type"] = "#microsoft.graph.webApp" - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.count = savebackup( self.directory.path, @@ -350,7 +365,7 @@ def test_backup_other_app(self): """The folder should be created, the file should be created, and the count should be 1.""" self.app_base_data["value"][0]["@odata.type"] = "#microsoft.graph.macOSother" - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.count = savebackup( self.directory.path, @@ -388,7 +403,7 @@ def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.app_base_data["value"][0]["@odata.type"] = "#microsoft.graph.iosVppApp" - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.count = savebackup( self.directory.path, "json", self.exclude, self.token, True, False, False @@ -403,7 +418,7 @@ def test_backup_append_id(self): def test_backup_scope_tag_and_audit(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.app_base_data["value"][0]["@odata.type"] = "#microsoft.graph.iosVppApp" - self.makeapirequest.return_value = self.app_base_data + self.makeapirequest.side_effect = [self.app_base_data, self.scope_tag] self.count = savebackup( self.directory.path, @@ -411,7 +426,7 @@ def test_backup_scope_tag_and_audit(self): self.exclude, self.token, True, - False, + True, [{"id": 0, "displayName": "default"}], ) From 5040227783fb60e299334ba0038d4231682b2be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:19:27 +0100 Subject: [PATCH 14/35] patch time.sleep to not have to wait --- tests/test_graph_batch.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/test_graph_batch.py b/tests/test_graph_batch.py index a80dc1ad..fb33c801 100644 --- a/tests/test_graph_batch.py +++ b/tests/test_graph_batch.py @@ -18,6 +18,7 @@ ) +@patch("time.sleep", return_value=None) class TestGraphBatch(unittest.TestCase): """Test class for graph_batch.""" @@ -123,7 +124,7 @@ def tearDown(self): self.batch_request.stop() del os.environ["VERBOSE"] - def test_batch_request(self): + def test_batch_request(self, _): """The batch request function should return the expected result.""" self.expected_result = [ @@ -146,7 +147,7 @@ def test_batch_request(self): self.assertEqual(self.result, self.expected_result) - def test_batch_request_429(self): + def test_batch_request_429(self, _): """The batch request function should return the expected result.""" self.expected_result = [ @@ -192,7 +193,7 @@ def test_batch_request_429(self): self.assertEqual(self.makeapirequestPost.call_count, 2) self.assertEqual(self.result, self.expected_result) - def test_batch_request_503(self): + def test_batch_request_503(self, _): """The batch request function should return the expected result.""" self.expected_result = [ @@ -238,7 +239,7 @@ def test_batch_request_503(self): self.assertEqual(self.makeapirequestPost.call_count, 2) self.assertEqual(self.result, self.expected_result) - def test_batch_assignment(self): + def test_batch_assignment(self, _): """The batch assignment function should return the expected result.""" self.expected_result = [ @@ -262,7 +263,7 @@ def test_batch_assignment(self): self.assertEqual(self.result, self.expected_result) - def test_batch_assignment_expand_assignments(self): + def test_batch_assignment_expand_assignments(self, _): """The batch assignment function should return the expected result.""" self.responses = [ @@ -307,7 +308,9 @@ def test_batch_assignment_expand_assignments(self): self.assertEqual(self.result, self.expected_result) - def test_batch_assignment_appProtection_mdmWindowsInformationProtectionPolicy(self): + def test_batch_assignment_appProtection_mdmWindowsInformationProtectionPolicy( + self, _ + ): """The batch assignment function should return the expected result for the platform.""" self.batch_assignment_data = { @@ -340,7 +343,7 @@ def test_batch_assignment_appProtection_mdmWindowsInformationProtectionPolicy(se self.assertEqual(self.result, self.expected_result) - def test_batch_assignment_appProtection_windowsInformationProtectionPolicy(self): + def test_batch_assignment_appProtection_windowsInformationProtectionPolicy(self, _): """The batch assignment function should return the expected result for the platform.""" self.batch_assignment_data = { @@ -373,7 +376,7 @@ def test_batch_assignment_appProtection_windowsInformationProtectionPolicy(self) self.assertEqual(self.result, self.expected_result) - def test_batch_assignment_appProtection_iosManagedAppProtection(self): + def test_batch_assignment_appProtection_iosManagedAppProtection(self, _): """The batch assignment function should return the expected result for the platform.""" self.batch_assignment_data = { @@ -403,7 +406,7 @@ def test_batch_assignment_appProtection_iosManagedAppProtection(self): self.assertEqual(self.result, self.expected_result) - def test_batch_intents(self): + def test_batch_intents(self, _): """The batch intents function should return the expected result.""" self.batch_request.side_effect = ( @@ -434,7 +437,7 @@ def test_batch_intents(self): self.assertEqual(self.result, self.expected_result) - def test_get_object_assignment(self): + def test_get_object_assignment(self, _): """The get object assignment function should return the expected result.""" self.id = "0" @@ -450,7 +453,7 @@ def test_get_object_assignment(self): self.assertEqual(self.result, self.expected_result) - def test_get_object_details(self): + def test_get_object_details(self, _): """The get object details function should return the expected result.""" self.id = "0" From 8f56893b87e878c5c823ad432d79ad2f43614bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:19:46 +0100 Subject: [PATCH 15/35] add audit request test --- tests/test_graph_request.py | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/test_graph_request.py b/tests/test_graph_request.py index 1de701aa..71540976 100644 --- a/tests/test_graph_request.py +++ b/tests/test_graph_request.py @@ -15,6 +15,7 @@ makeapirequestPatch, makeapirequestPost, makeapirequestPut, + makeAuditRequest, ) @@ -431,5 +432,44 @@ def test_makeapirequestDelete_not_matching_status_code(self, mock_patch, _): self.assertEqual(1, mock_patch.call_count) +@patch("src.IntuneCD.intunecdlib.graph_request.makeAuditRequest") +@patch("requests.get") +@patch("time.sleep", return_value=None) +class TestGraphAuditRequest(unittest.TestCase): + """Test class for graph_request.""" + + def setUp(self): + self.token = {"access_token": "token"} + + def test_makeAuditRequest(self, _, mock_get, __): + """The request should be made and the response should be returned.""" + self.mock_resp = _mock_response( + self, + status=200, + content=( + '{"value": [{"resources": [{"resourceId": "0", "auditResourceType": "MagicResource"}],' + '"activityDateTime": "2021-01-01T00:00:00Z", "activityOperationType": "Patch", ' + '"activityResult": "Success", "actor": {"auditActorType": "ItPro", "userPrincipalName": "test"}}]}' + ), + ) + mock_get.return_value = self.mock_resp + self.result = makeAuditRequest( + "componentName eq 'MobileAppConfiguration'", self.token + ) + self.assertEqual( + self.result, + [ + { + "resourceId": "0", + "auditResourceType": "MagicResource", + "actor": "test", + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + } + ], + ) + + if __name__ == "__main__": unittest.main() From 6fef433be85440ba094d73fed0473606b232cbcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:20:09 +0100 Subject: [PATCH 16/35] create test_process_audit_data.py --- tests/test_process_audit_data.py | 193 +++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 tests/test_process_audit_data.py diff --git a/tests/test_process_audit_data.py b/tests/test_process_audit_data.py new file mode 100644 index 00000000..dc069f83 --- /dev/null +++ b/tests/test_process_audit_data.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- +import unittest +from unittest.mock import patch + +from src.IntuneCD.intunecdlib.process_audit_data import ( + _check_if_git_repo, + _configure_git, + _get_payload_from_audit_data, + _git_check_modified, + _git_check_new_file, + _git_commit_changes, + _git_installed, + process_audit_data, +) + + +class TestProcessAuditData(unittest.TestCase): + """ + Test process audit data + """ + + @patch("src.IntuneCD.intunecdlib.process_audit_data.subprocess.run") + def test_configure_git(self, mock_run): + """ + Test configure git + """ + self.record = { + "activityDateTime": "2021-05-25T20:00:00Z", + "userPrincipalName": "test", + "actor": "test", + } + mock_run.return_value.returncode = 0 + self.assertIsNone(_configure_git(self.record, "path")) + + @patch("src.IntuneCD.intunecdlib.process_audit_data.subprocess.run") + def test_git_installed(self, mock_run): + """ + Test git installed + """ + mock_run.return_value.returncode = 0 + self.assertTrue(_git_installed()) + + mock_run.return_value.returncode = 1 + self.assertFalse(_git_installed()) + + @patch("src.IntuneCD.intunecdlib.process_audit_data.subprocess.run") + def test_check_if_git_repo(self, mock_run): + """ + Test check if git repo + """ + mock_run.return_value.stdout = "true" + self.assertTrue(_check_if_git_repo("path", "file")) + + mock_run.return_value.stdout = "false" + self.assertFalse(_check_if_git_repo("path", "file")) + + @patch("src.IntuneCD.intunecdlib.process_audit_data.subprocess.run") + def test_git_check_modified(self, mock_run): + """ + Test git check modified + """ + mock_run.return_value.stdout = "modified" + self.assertTrue(_git_check_modified("path", "file")) + + mock_run.return_value.stdout = "" + self.assertFalse(_git_check_modified("path", "file")) + + @patch("src.IntuneCD.intunecdlib.process_audit_data.subprocess.run") + def test_git_check_new_file(self, mock_run): + """ + Test git check new file + """ + mock_run.return_value.stderr = "did not match any file(s) known to git" + self.assertTrue(_git_check_new_file("path", "file")) + + mock_run.return_value.stderr = "" + self.assertFalse(_git_check_new_file("path", "file")) + + @patch("src.IntuneCD.intunecdlib.process_audit_data.subprocess.run") + def test_git_commit_changes(self, mock_run): + """ + Test git commit changes + """ + mock_run.return_value.returncode = 0 + self.record = { + "activityDateTime": "2021-05-25T20:00:00Z", + "userPrincipalName": "test", + "actor": "test", + "activityOperationType": "test", + "activityResult": "test", + } + self.assertIsNone(_git_commit_changes(self.record, "path", "file")) + + mock_run.return_value.returncode = 1 + self.assertIsNone(_git_commit_changes(self.record, "path", "file")) + + def test_get_payload_from_audit_data(self): + """ + Test get payload from audit data + """ + self.record = [ + { + "activityDateTime": "2021-05-25T20:00:00Z", + "userPrincipalName": "test", + "actor": "test", + "activityOperationType": "test", + "activityResult": "test", + "test": "test", + } + ] + self.compare_data = {"type": "test", "value": "test"} + + self.assertIsNotNone( + _get_payload_from_audit_data(self.record, self.compare_data) + ) + + @patch("src.IntuneCD.intunecdlib.process_audit_data._check_if_git_repo") + @patch("src.IntuneCD.intunecdlib.process_audit_data._configure_git") + @patch("src.IntuneCD.intunecdlib.process_audit_data._git_installed") + @patch("src.IntuneCD.intunecdlib.process_audit_data._get_payload_from_audit_data") + @patch("src.IntuneCD.intunecdlib.process_audit_data._git_check_modified") + @patch("src.IntuneCD.intunecdlib.process_audit_data._git_commit_changes") + def test_process_audit_data( + self, + mock_get_payload_from_audit_data, + mock_git_installed, + mock_configure_git, + mock_check_if_git_repo, + mock_git_check_modified, + _, + ): + """ + Test process audit data + """ + mock_get_payload_from_audit_data.return_value = { + "activityDateTime": "2021-05-25T20:00:00Z", + "userPrincipalName": "test", + "actor": "test", + "activityOperationType": "test", + "activityResult": "test", + "test": "test", + } + mock_git_installed.return_value = True + mock_check_if_git_repo.return_value = True + self.assertIsNone( + process_audit_data("audit_data", "compare_data", "path", "file") + ) + + mock_git_installed.return_value = False + self.assertIsNone( + process_audit_data("audit_data", "compare_data", "path", "file") + ) + + mock_git_installed.return_value = True + mock_check_if_git_repo.return_value = False + self.assertIsNone( + process_audit_data("audit_data", "compare_data", "path", "file") + ) + + mock_git_installed.return_value = True + mock_check_if_git_repo.return_value = True + mock_configure_git.return_value = None + mock_git_check_modified.return_value = "yes" + + self.assertFalse( + process_audit_data("audit_data", "compare_data", "path", "file") + ) + + @patch("src.IntuneCD.intunecdlib.process_audit_data._check_if_git_repo") + @patch("src.IntuneCD.intunecdlib.process_audit_data._configure_git") + @patch("src.IntuneCD.intunecdlib.process_audit_data._git_installed") + @patch("src.IntuneCD.intunecdlib.process_audit_data._get_payload_from_audit_data") + def test_process_audit_data_no_record( + self, + mock_get_payload_from_audit_data, + mock_git_installed, + _, + mock_check_if_git_repo, + ): + """ + Test process audit data no records + """ + mock_get_payload_from_audit_data.return_value = {} + mock_git_installed.return_value = True + mock_check_if_git_repo.return_value = True + + self.assertFalse( + process_audit_data("audit_data", "compare_data", "path", "file") + ) + + +if __name__ == "__main__": + unittest.main() From f5307445cbe8029d8d2739f3bd72af69f65b3dbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:20:20 +0100 Subject: [PATCH 17/35] create test_process_scope_tags.py --- tests/test_process_scope_tags.py | 44 ++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/test_process_scope_tags.py diff --git a/tests/test_process_scope_tags.py b/tests/test_process_scope_tags.py new file mode 100644 index 00000000..fe6ec47d --- /dev/null +++ b/tests/test_process_scope_tags.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +This module tests the process_scope_tags function. +""" + +import unittest +from unittest.mock import patch + +from src.IntuneCD.intunecdlib.process_scope_tags import get_scope_tags + + +class TestGetScopeTags(unittest.TestCase): + """Test class for get_scope_tags.""" + + def setUp(self): + self.data = {"id": "1", "displayName": "Test"} + self.token = {"access_token": "test"} + + self.get_scope_tags_patch = patch( + "src.IntuneCD.intunecdlib.process_scope_tags.get_scope_tags" + ) + self.get_scope_tags = self.get_scope_tags_patch.start() + self.get_scope_tags.return_value = [self.data] + + self.makeapirequest_patch = patch( + "src.IntuneCD.intunecdlib.process_scope_tags.makeapirequest" + ) + self.makeapirequest = self.makeapirequest_patch.start() + self.makeapirequest.return_value = {"value": [self.data]} + + def tearDown(self): + self.get_scope_tags_patch.stop() + + def test_get_scope_tags(self): + """The odata type should match the expected value.""" + self.result = get_scope_tags(self.token) + + self.assertEqual(self.result, [self.data]) + + +if __name__ == "__main__": + unittest.main() From 649c1396e5835c3696454b55bf889f1f7031dbd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:22:19 +0100 Subject: [PATCH 18/35] formatting --- src/IntuneCD/backup/Intune/backup_applications.py | 2 +- src/IntuneCD/intunecdlib/graph_request.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/IntuneCD/backup/Intune/backup_applications.py b/src/IntuneCD/backup/Intune/backup_applications.py index 88ad4dc4..0e6fab7a 100644 --- a/src/IntuneCD/backup/Intune/backup_applications.py +++ b/src/IntuneCD/backup/Intune/backup_applications.py @@ -10,8 +10,8 @@ from ...intunecdlib.clean_filename import clean_filename from ...intunecdlib.graph_batch import ( batch_assignment, - get_object_assignment, batch_request, + get_object_assignment, ) from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest from ...intunecdlib.process_audit_data import process_audit_data diff --git a/src/IntuneCD/intunecdlib/graph_request.py b/src/IntuneCD/intunecdlib/graph_request.py index b32f81ad..128ae3f9 100644 --- a/src/IntuneCD/intunecdlib/graph_request.py +++ b/src/IntuneCD/intunecdlib/graph_request.py @@ -9,6 +9,7 @@ import json import os import time + import requests from .logger import log From 998e01932b144bea117fe19c8a83ec9ed6b4e148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:23:20 +0100 Subject: [PATCH 19/35] bump to 2.2.0.beta4 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index bf2dae75..9b0a56f0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = IntuneCD -version = 2.2.0.beta3 +version = 2.2.0.beta4 author = Tobias Almén author_email = almenscorner@outlook.com description = Tool to backup and update configurations in Intune From 7f4dddae2786c8092d4aae2abb5d9e7795a46c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Thu, 29 Feb 2024 08:40:07 +0100 Subject: [PATCH 20/35] improve coverage --- .../test_backup_appleEnrollmentProfile.py | 24 +++- .../Intune/test_backup_assignmentFilter.py | 18 ++- tests/Backup/Intune/test_backup_compliance.py | 26 +++- .../test_backup_configurationPolicies.py | 27 +++- .../Intune/test_backup_deviceCategories.py | 19 ++- .../test_backup_notificationTemplate.py | 11 ++ tests/Backup/Intune/test_backup_profiles.py | 136 +++++++++++++++++- .../Backup/Intune/test_backup_shellScripts.py | 2 +- 8 files changed, 250 insertions(+), 13 deletions(-) diff --git a/tests/Backup/Intune/test_backup_appleEnrollmentProfile.py b/tests/Backup/Intune/test_backup_appleEnrollmentProfile.py index 0c524350..70cce26e 100644 --- a/tests/Backup/Intune/test_backup_appleEnrollmentProfile.py +++ b/tests/Backup/Intune/test_backup_appleEnrollmentProfile.py @@ -4,6 +4,7 @@ """This module tests backing up Apple Enrollment Profile.""" import json +import os.path import unittest from pathlib import Path from unittest.mock import patch @@ -153,12 +154,31 @@ def test_backup_with_no_return_data(self): def test_backup_with_prefix(self): """The count should be 0 if no data is returned.""" - self.makeapirequest.return_value = {"value": []} + self.batch_intune[0]["value"][0]["displayName"] = "test - test1" + self.batch_request.return_value = self.batch_intune self.count = savebackup( self.directory.path, "json", self.token, "test", self.append_id, False ) - self.assertEqual(0, self.count["config_count"]) + self.assertEqual(1, self.count["config_count"]) + self.assertTrue( + os.path.exists( + f"{self.directory.path}/Enrollment Profiles/Apple/test - test1.json" + ) + ) + + def test_backup_with_prefix_no_match(self): + """The count should be 0 if no data is returned.""" + + self.makeapirequest.return_value = self.token_response + self.batch_request.return_value = self.batch_intune + self.count = savebackup( + self.directory.path, "json", self.token, "prefix", self.append_id, False + ) + + self.assertFalse( + os.path.exists(f"{self.directory.path}/Enrollment Profiles/Apple/test.json") + ) def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" diff --git a/tests/Backup/Intune/test_backup_assignmentFilter.py b/tests/Backup/Intune/test_backup_assignmentFilter.py index a5ea80c1..5f3487c3 100644 --- a/tests/Backup/Intune/test_backup_assignmentFilter.py +++ b/tests/Backup/Intune/test_backup_assignmentFilter.py @@ -4,6 +4,7 @@ """This module tests backing up assignment filters.""" import json +import os.path import unittest from pathlib import Path from unittest.mock import patch @@ -114,9 +115,20 @@ def test_backup_with_no_return_data(self): def test_backup_with_prefix(self): """The count should be 0 if no data is returned.""" - self.makeapirequest.return_value = {"value": []} + self.assignment_filter["value"][0]["displayName"] = "test1 - macos model" + self.count = savebackup( + self.directory.path, "json", self.token, "test1", True, False, "" + ) + self.assertEqual(1, self.count["config_count"]) + self.assertTrue( + os.path.exists(f"{self.directory.path}/Filters/test1 - macos model__0.json") + ) + + def test_backup_with_prefix_no_match(self): + """The count should be 0 if no data is returned.""" + self.count = savebackup( - self.directory.path, "json", self.token, "test", self.append_id, False, "" + self.directory.path, "json", self.token, "test1", True, False, "" ) self.assertEqual(0, self.count["config_count"]) @@ -139,7 +151,7 @@ def test_backup_scope_tag_and_audit(self): self.token, "", True, - False, + True, [{"id": 0, "displayName": "default"}], ) self.assertTrue( diff --git a/tests/Backup/Intune/test_backup_compliance.py b/tests/Backup/Intune/test_backup_compliance.py index 87d1f9cd..25b60654 100644 --- a/tests/Backup/Intune/test_backup_compliance.py +++ b/tests/Backup/Intune/test_backup_compliance.py @@ -4,6 +4,7 @@ """This module tests backing up compliance.""" import json +import os.path import unittest from pathlib import Path from unittest.mock import patch @@ -172,7 +173,28 @@ def test_backup_with_no_returned_data(self): def test_backup_with_prefix(self): """The count should be 0 if no data is returned.""" - self.makeapirequest.return_value = {"value": []} + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "test", + self.append_id, + False, + None, + ) + self.assertEqual(1, self.count["config_count"]) + self.assertTrue( + os.path.exists( + f"{self.directory.path}/Compliance Policies/Policies/test_iosCompliancePolicy.json" + ) + ) + + def test_backup_with_prefix_no_match(self): + """The count should be 0 if no data is returned.""" + + self.compliance_policy["value"][0]["displayName"] = "iosCompliancePolicy" + self.makeapirequest.return_value = self.compliance_policy self.count = savebackup( self.directory.path, "json", @@ -208,7 +230,7 @@ def test_backup_scope_tags_and_audit(self): self.token, "", True, - False, + True, [{"id": 0, "displayName": "default"}], ) diff --git a/tests/Backup/Intune/test_backup_configurationPolicies.py b/tests/Backup/Intune/test_backup_configurationPolicies.py index 5e34902b..48a38837 100644 --- a/tests/Backup/Intune/test_backup_configurationPolicies.py +++ b/tests/Backup/Intune/test_backup_configurationPolicies.py @@ -4,6 +4,7 @@ """This module tests backing up App Configuration.""" import json +import os.path import unittest from pathlib import Path from unittest.mock import patch @@ -206,7 +207,9 @@ def test_backup_with_no_returned_data(self): def test_backup_with_prefix(self): """The count should be 0 if no data is returned.""" - self.makeapirequest.return_value = {"value": []} + self.configuration_policy["value"][0]["name"] = "test_test" + self.makeapirequest.return_value = self.configuration_policy + self.count = savebackup( self.directory.path, "json", @@ -217,6 +220,26 @@ def test_backup_with_prefix(self): False, None, ) + self.assertEqual(1, self.count["config_count"]) + self.assertTrue( + os.path.exists( + f"{self.directory.path}/Settings Catalog/test_test_test.json" + ) + ) + + def test_backup_with_prefix_no_match(self): + """The count should be 0 if no data is returned.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "prefix", + self.append_id, + False, + None, + ) self.assertEqual(0, self.count["config_count"]) def test_backup_append_id(self): @@ -240,7 +263,7 @@ def test_backup_scope_tag_and_audit(self): self.token, "", True, - False, + True, [{"id": 0, "displayName": "default"}], ) diff --git a/tests/Backup/Intune/test_backup_deviceCategories.py b/tests/Backup/Intune/test_backup_deviceCategories.py index ec5f2f1d..162ed4fa 100644 --- a/tests/Backup/Intune/test_backup_deviceCategories.py +++ b/tests/Backup/Intune/test_backup_deviceCategories.py @@ -4,6 +4,7 @@ """This module tests backing up deviceCategories.""" import json +import os.path import unittest from pathlib import Path from unittest.mock import patch @@ -112,7 +113,23 @@ def test_backup_with_no_return_data(self): def test_backup_with_prefix(self): """The count should be 0 if no data is returned.""" - self.makeapirequest.return_value = {"value": []} + self.deviceCategories["value"][0]["displayName"] = "test_Test1" + self.makeapirequest.return_value = self.deviceCategories + + self.count = savebackup( + self.directory.path, "json", self.token, "test", self.append_id, False, "" + ) + self.assertEqual(1, self.count["config_count"]) + self.assertTrue( + os.path.exists(f"{self.directory.path}/Device Categories/test_Test1.json") + ) + + def test_backup_with_prefix_no_match(self): + """The count should be 0 if no data is returned.""" + + self.deviceCategories["value"][0]["displayName"] = "category" + self.makeapirequest.return_value = self.deviceCategories + self.count = savebackup( self.directory.path, "json", self.token, "test", self.append_id, False, "" ) diff --git a/tests/Backup/Intune/test_backup_notificationTemplate.py b/tests/Backup/Intune/test_backup_notificationTemplate.py index 7fc2cbe7..0dd2059a 100644 --- a/tests/Backup/Intune/test_backup_notificationTemplate.py +++ b/tests/Backup/Intune/test_backup_notificationTemplate.py @@ -162,6 +162,17 @@ def test_backup_with_prefix(self): ) self.assertEqual(0, self.count["config_count"]) + def test_backup_EnrollmentNotificationInternalMEO(self): + """The count should be 0 if no data is returned.""" + + self.message_template["value"][0][ + "displayName" + ] = "EnrollmentNotificationInternalMEO" + self.count = savebackup( + self.directory.path, "json", self.token, "", self.append_id, False, "" + ) + self.assertEqual(0, self.count["config_count"]) + def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" diff --git a/tests/Backup/Intune/test_backup_profiles.py b/tests/Backup/Intune/test_backup_profiles.py index 2ca7a623..7e107171 100644 --- a/tests/Backup/Intune/test_backup_profiles.py +++ b/tests/Backup/Intune/test_backup_profiles.py @@ -4,6 +4,7 @@ """This module tests backing up profiles.""" +import json import unittest from pathlib import Path from unittest.mock import patch @@ -197,6 +198,65 @@ def test_backup_windows_custom_profile_encrypted(self): ) self.assertEqual(1, self.count["config_count"]) + def test_backup_windows_custom_profile_encrypted_ignore_omas(self): + """The file should be created and the count should be 1.""" + + self.profile = { + "value": [ + { + "@odata.type": "#microsoft.graph.windows10CustomConfiguration", + "id": "0", + "displayName": "test", + "omaSettings": [ + { + "isEncrypted": True, + "@odata.type": "#microsoft.graph.windows10OmaSetting", + "secretReferenceValueId": "0", + "omaUri": "test uri", + "displayName": "test", + "description": "", + "value": "encrypted value", + } + ], + } + ] + } + self.oma_values = { + "@odata.context": "https://graph.microsoft.com/beta/$metadata#Edm.String", + "value": "password", + } + + self.makeapirequest.side_effect = self.profile, self.oma_values + + self.count = savebackup( + self.directory.path, + "json", + self.token, + self.exclude, + "", + self.append_id, + True, + False, + None, + ) + + with open( + f"{self.directory.path}/Device Configurations/test_windows10CustomConfiguration.json", + "r", + encoding="utf-8", + ) as file: + data = file.read() + data = json.loads(data) + print(data) + self.assertTrue("password" not in data["omaSettings"][0]["value"]) + + self.assertTrue( + Path( + f"{self.directory.path}/Device Configurations/test_windows10CustomConfiguration.json" + ).exists() + ) + self.assertEqual(1, self.count["config_count"]) + def test_backup_windows_custom_profile_not_encrypted(self): """The file should be created and the count should be 1.""" @@ -246,15 +306,17 @@ def test_backup_windows_custom_profile_not_encrypted(self): ) self.assertEqual(1, self.count["config_count"]) - def test_backup_scope_tags_and_audit(self): + def test_backup_scope_tags_and_audit_macOS_custom_profile(self): """The folders and files should be created and the count should be 2.""" self.makeapirequest.return_value = { "value": [ { - "@odata.type": "#microsoft.graph.test", + "@odata.type": "#microsoft.graph.macOSCustomConfiguration", "id": "0", "displayName": "test", + "payload": "SGkgdGhlcmUgcHJldHR5", + "payloadFileName": "test.mobileconfig", } ] } @@ -267,7 +329,51 @@ def test_backup_scope_tags_and_audit(self): "", self.append_id, False, + True, + [{"id": 0, "displayName": "default"}], + ) + + self.assertEqual(2, self.count["config_count"]) + + def test_backup_scope_tags_and_audit_windows_custom_profile(self): + """The folders and files should be created and the count should be 2.""" + + self.profile = { + "value": [ + { + "@odata.type": "#microsoft.graph.windows10CustomConfiguration", + "id": "0", + "displayName": "test", + "omaSettings": [ + { + "isEncrypted": False, + "@odata.type": "#microsoft.graph.windows10OmaSetting", + "secretReferenceValueId": "0", + "omaUri": "test uri", + "displayName": "test", + "description": "", + "value": [], + } + ], + } + ] + } + self.oma_values = { + "@odata.context": "https://graph.microsoft.com/beta/$metadata#Edm.String", + "value": "password", + } + + self.makeapirequest.side_effect = self.profile, self.oma_values + + self.count = savebackup( + self.directory.path, + "json", + self.token, + self.exclude, + "", + self.append_id, False, + True, [{"id": 0, "displayName": "default"}], ) @@ -376,6 +482,32 @@ def test_backup_with_prefix(self): ) self.assertEqual(0, self.count["config_count"]) + def test_backup_prefix_no_match(self): + """The count should be 0 if no data is returned.""" + + self.makeapirequest.return_value = { + "value": [ + { + "@odata.type": "#microsoft.graph.macOSGeneralDeviceConfiguration", + "id": "0", + "displayName": "test", + } + ] + } + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "test1", + self.append_id, + False, + False, + None, + ) + self.assertEqual(0, self.count["config_count"]) + def test_backup_append_id(self): """The folder should be created, the file should have the expected contents, and the count should be 1.""" self.makeapirequest.return_value = { diff --git a/tests/Backup/Intune/test_backup_shellScripts.py b/tests/Backup/Intune/test_backup_shellScripts.py index a8e79a9e..4eeeaff2 100644 --- a/tests/Backup/Intune/test_backup_shellScripts.py +++ b/tests/Backup/Intune/test_backup_shellScripts.py @@ -214,7 +214,7 @@ def test_backup_scope_tag_and_audit(self): self.token, "", True, - False, + True, [{"id": 0, "displayName": "default"}], ) From dffc7ab477afb013c395b9f67cee42a59e2da535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Thu, 29 Feb 2024 08:40:40 +0100 Subject: [PATCH 21/35] fix scope tag bug when creating policy --- src/IntuneCD/update/Intune/update_appConfiguration.py | 7 ++++--- src/IntuneCD/update/Intune/update_appProtection.py | 7 ++++--- src/IntuneCD/update/Intune/update_assignmentFilter.py | 5 +++-- src/IntuneCD/update/Intune/update_compliance.py | 5 +++-- src/IntuneCD/update/Intune/update_configurationPolicies.py | 5 +++-- .../update/Intune/update_customAttributeShellScript.py | 5 +++-- src/IntuneCD/update/Intune/update_deviceCategories.py | 5 +++-- .../update/Intune/update_enrollmentConfigurations.py | 5 +++-- src/IntuneCD/update/Intune/update_enrollmentStatusPage.py | 5 +++-- .../update/Intune/update_groupPolicyConfiguration.py | 6 ++++-- src/IntuneCD/update/Intune/update_managementIntents.py | 5 +++-- src/IntuneCD/update/Intune/update_notificationTemplate.py | 7 +++---- src/IntuneCD/update/Intune/update_powershellScripts.py | 5 +++-- src/IntuneCD/update/Intune/update_proactiveRemediation.py | 5 +++-- src/IntuneCD/update/Intune/update_profiles.py | 5 +++-- src/IntuneCD/update/Intune/update_roles.py | 5 +++-- src/IntuneCD/update/Intune/update_shellScripts.py | 5 +++-- src/IntuneCD/update/Intune/update_windowsDriverUpdates.py | 5 +++-- .../update/Intune/update_windowsEnrollmentProfile.py | 5 +++-- src/IntuneCD/update/Intune/update_windowsFeatureUpdates.py | 5 +++-- src/IntuneCD/update/Intune/update_windowsQualityUpdates.py | 5 +++-- 21 files changed, 66 insertions(+), 46 deletions(-) diff --git a/src/IntuneCD/update/Intune/update_appConfiguration.py b/src/IntuneCD/update/Intune/update_appConfiguration.py index 44b46bc9..bb87b6fb 100644 --- a/src/IntuneCD/update/Intune/update_appConfiguration.py +++ b/src/IntuneCD/update/Intune/update_appConfiguration.py @@ -81,6 +81,10 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + # Get scope tag ID + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + # If App Configuration exists, continue data = {"value": ""} if mem_data["value"]: @@ -94,9 +98,6 @@ def update( if data["value"]: print("-" * 90) - # Get scope tag ID - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value", {}).get("id", None) # Remove keys before using DeepDiff data = remove_keys(data) diff --git a/src/IntuneCD/update/Intune/update_appProtection.py b/src/IntuneCD/update/Intune/update_appProtection.py index 2a1f3217..bb55dc58 100644 --- a/src/IntuneCD/update/Intune/update_appProtection.py +++ b/src/IntuneCD/update/Intune/update_appProtection.py @@ -87,6 +87,10 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + # Get scope tag ID + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + # If App Protection exists, continue data = {"value": ""} if mem_data["value"]: @@ -111,9 +115,6 @@ def update( if data["value"]: print("-" * 90) - # Get scope tag ID - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value", {}).get("id", None) # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update/Intune/update_assignmentFilter.py b/src/IntuneCD/update/Intune/update_assignmentFilter.py index 97dbdedd..cc931265 100644 --- a/src/IntuneCD/update/Intune/update_assignmentFilter.py +++ b/src/IntuneCD/update/Intune/update_assignmentFilter.py @@ -49,6 +49,9 @@ def update(path, token, report, scope_tags): with open(file, encoding="utf-8") as f: repo_data = load_file(filename, f) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + filter_value = {} # If Filter exists, continue @@ -59,8 +62,6 @@ def update(path, token, report, scope_tags): if filter_value: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) filter_id = filter_value["id"] filter_value = remove_keys(filter_value) diff --git a/src/IntuneCD/update/Intune/update_compliance.py b/src/IntuneCD/update/Intune/update_compliance.py index 38379424..c1a76e45 100644 --- a/src/IntuneCD/update/Intune/update_compliance.py +++ b/src/IntuneCD/update/Intune/update_compliance.py @@ -79,6 +79,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + # If Compliance Policy exists, continue data = {"value": ""} if mem_data["value"]: @@ -92,8 +95,6 @@ def update( if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value", {}).get("id", None) data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update/Intune/update_configurationPolicies.py b/src/IntuneCD/update/Intune/update_configurationPolicies.py index 4953a1b0..98b13a31 100644 --- a/src/IntuneCD/update/Intune/update_configurationPolicies.py +++ b/src/IntuneCD/update/Intune/update_configurationPolicies.py @@ -73,6 +73,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + data = {"value": ""} if mem_data["value"]: for val in mem_data["value"]: @@ -97,8 +100,6 @@ def update( # If Filter exists, continue if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) # Get Filter data from Intune mem_policy_data = makeapirequest( ENDPOINT + "/" + data.get("value").get("id"), token diff --git a/src/IntuneCD/update/Intune/update_customAttributeShellScript.py b/src/IntuneCD/update/Intune/update_customAttributeShellScript.py index b54e4b02..7b4b1d24 100644 --- a/src/IntuneCD/update/Intune/update_customAttributeShellScript.py +++ b/src/IntuneCD/update/Intune/update_customAttributeShellScript.py @@ -79,6 +79,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + data = {"value": ""} if mem_shellScript["value"]: for val in mem_shellScript["value"]: @@ -89,8 +92,6 @@ def update( # If Custom Attribute Shell script exists, continue if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) q_param = None # Get Shell script details mem_data = makeapirequest( diff --git a/src/IntuneCD/update/Intune/update_deviceCategories.py b/src/IntuneCD/update/Intune/update_deviceCategories.py index 569b8250..d7a00472 100644 --- a/src/IntuneCD/update/Intune/update_deviceCategories.py +++ b/src/IntuneCD/update/Intune/update_deviceCategories.py @@ -50,6 +50,9 @@ def update(path, token, report, remove, scope_tags): with open(file, encoding="utf-8") as f: repo_data = load_file(filename, f) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + category_value = {} # If Category exists, continue @@ -61,8 +64,6 @@ def update(path, token, report, remove, scope_tags): if category_value: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) category_id = category_value["id"] category_value = remove_keys(category_value) diff --git a/src/IntuneCD/update/Intune/update_enrollmentConfigurations.py b/src/IntuneCD/update/Intune/update_enrollmentConfigurations.py index a4eb484e..d8068b8b 100644 --- a/src/IntuneCD/update/Intune/update_enrollmentConfigurations.py +++ b/src/IntuneCD/update/Intune/update_enrollmentConfigurations.py @@ -79,6 +79,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + config_type = repo_data.get("deviceEnrollmentConfigurationType", None) config_type = config_type[0].upper() + config_type[1:] config_type = re.findall("[A-Z][^A-Z]*", config_type) @@ -114,8 +117,6 @@ def update( # If Enrollment Configuration exists, continue if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) # Get Enrollment Configuration data from Intune mem_id = data.get("value").get("id") mem_priority = data.get("value").get("priority") diff --git a/src/IntuneCD/update/Intune/update_enrollmentStatusPage.py b/src/IntuneCD/update/Intune/update_enrollmentStatusPage.py index cf5150ff..0c5e79fc 100644 --- a/src/IntuneCD/update/Intune/update_enrollmentStatusPage.py +++ b/src/IntuneCD/update/Intune/update_enrollmentStatusPage.py @@ -78,6 +78,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + data = {"value": ""} if mem_data["value"]: for val in mem_data["value"]: @@ -91,8 +94,6 @@ def update( # If Enrollment Status Page Profile exists, continue if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value").get("id") # Remove keys before using DeepDiff mem_data["value"][0] = remove_keys(mem_data["value"][0]) diff --git a/src/IntuneCD/update/Intune/update_groupPolicyConfiguration.py b/src/IntuneCD/update/Intune/update_groupPolicyConfiguration.py index 70248744..42d8a3ba 100644 --- a/src/IntuneCD/update/Intune/update_groupPolicyConfiguration.py +++ b/src/IntuneCD/update/Intune/update_groupPolicyConfiguration.py @@ -430,6 +430,10 @@ def update( if "assignments" in repo_data: assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + # If configurations was found in Intune, continue if mem_configs: for val in mem_configs[:]: @@ -445,8 +449,6 @@ def update( # If data was found, continue if data: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data["id"] data = remove_keys(data) diff --git a/src/IntuneCD/update/Intune/update_managementIntents.py b/src/IntuneCD/update/Intune/update_managementIntents.py index 8ffee9dc..cf52eab2 100644 --- a/src/IntuneCD/update/Intune/update_managementIntents.py +++ b/src/IntuneCD/update/Intune/update_managementIntents.py @@ -82,6 +82,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + mem_data = {} for intent in intent_responses["value"]: if ( @@ -98,8 +101,6 @@ def update( # If Intent exists, continue if mem_data: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) print( "Checking if Intent: " + repo_data["displayName"] diff --git a/src/IntuneCD/update/Intune/update_notificationTemplate.py b/src/IntuneCD/update/Intune/update_notificationTemplate.py index 2006bf07..6b777d79 100644 --- a/src/IntuneCD/update/Intune/update_notificationTemplate.py +++ b/src/IntuneCD/update/Intune/update_notificationTemplate.py @@ -54,6 +54,9 @@ def update(path, token, report, remove, scope_tags): with open(file, encoding="utf-8") as f: repo_data = load_file(filename, f) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + data = {"value": ""} if mem_data["value"]: for val in mem_data["value"]: @@ -66,10 +69,6 @@ def update(path, token, report, remove, scope_tags): # If Notification Template exists, continue if data["value"]: print("-" * 90) - if scope_tags: - repo_data["roleScopeTagIds"] = get_scope_tags_id( - repo_data, scope_tags - ) # Get Notification Template data from Intune q_param = "?$expand=localizedNotificationMessages" mem_template_data = makeapirequest( diff --git a/src/IntuneCD/update/Intune/update_powershellScripts.py b/src/IntuneCD/update/Intune/update_powershellScripts.py index 8845c32d..9e4b7897 100644 --- a/src/IntuneCD/update/Intune/update_powershellScripts.py +++ b/src/IntuneCD/update/Intune/update_powershellScripts.py @@ -77,6 +77,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + data = {"value": ""} if mem_powershellScript["value"]: for val in mem_powershellScript["value"]: @@ -87,8 +90,6 @@ def update( # If Powershell script exists, continue if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) # Get Powershell script details mem_data = makeapirequest( ENDPOINT + "/" + data.get("value").get("id"), token diff --git a/src/IntuneCD/update/Intune/update_proactiveRemediation.py b/src/IntuneCD/update/Intune/update_proactiveRemediation.py index b3d96386..ea19fe16 100644 --- a/src/IntuneCD/update/Intune/update_proactiveRemediation.py +++ b/src/IntuneCD/update/Intune/update_proactiveRemediation.py @@ -77,6 +77,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + data = {"value": ""} if mem_proactiveRemediation["value"]: for val in mem_proactiveRemediation["value"]: @@ -87,8 +90,6 @@ def update( # If Powershell script exists, continue if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) q_param = None # Get Powershell script details mem_data = makeapirequest( diff --git a/src/IntuneCD/update/Intune/update_profiles.py b/src/IntuneCD/update/Intune/update_profiles.py index 13b4aec7..8ee69e14 100644 --- a/src/IntuneCD/update/Intune/update_profiles.py +++ b/src/IntuneCD/update/Intune/update_profiles.py @@ -74,6 +74,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + # If Device Configuration exists, continue data = {"value": ""} if mem_data["value"]: @@ -87,8 +90,6 @@ def update( if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value").get("id") # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update/Intune/update_roles.py b/src/IntuneCD/update/Intune/update_roles.py index 1db6bd83..d5c10479 100644 --- a/src/IntuneCD/update/Intune/update_roles.py +++ b/src/IntuneCD/update/Intune/update_roles.py @@ -52,6 +52,9 @@ def update(path, token, report, remove=False, scope_tags=None): with open(file, encoding="utf-8") as f: repo_data = load_file(filename, f) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + role_value = {} # If Filter exists, continue @@ -63,8 +66,6 @@ def update(path, token, report, remove=False, scope_tags=None): if role_value: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) role_id = role_value["id"] role_value = remove_keys(role_value) diff --git a/src/IntuneCD/update/Intune/update_shellScripts.py b/src/IntuneCD/update/Intune/update_shellScripts.py index 44be42f7..22b0c916 100644 --- a/src/IntuneCD/update/Intune/update_shellScripts.py +++ b/src/IntuneCD/update/Intune/update_shellScripts.py @@ -79,6 +79,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + data = {"value": ""} if mem_shellScript["value"]: for val in mem_shellScript["value"]: @@ -89,8 +92,6 @@ def update( # If Shell script exists, continue if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) q_param = None # Get Shell script details mem_data = makeapirequest( diff --git a/src/IntuneCD/update/Intune/update_windowsDriverUpdates.py b/src/IntuneCD/update/Intune/update_windowsDriverUpdates.py index fb0f9c35..7286dfe9 100644 --- a/src/IntuneCD/update/Intune/update_windowsDriverUpdates.py +++ b/src/IntuneCD/update/Intune/update_windowsDriverUpdates.py @@ -78,6 +78,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + data = {"value": ""} if mem_data["value"]: for val in mem_data["value"]: @@ -88,8 +91,6 @@ def update( # If Windows Driver Update Profile exists, continue if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value").get("id") # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update/Intune/update_windowsEnrollmentProfile.py b/src/IntuneCD/update/Intune/update_windowsEnrollmentProfile.py index 38b7dca5..008aeea0 100644 --- a/src/IntuneCD/update/Intune/update_windowsEnrollmentProfile.py +++ b/src/IntuneCD/update/Intune/update_windowsEnrollmentProfile.py @@ -76,6 +76,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + data = {"value": ""} if mem_data["value"]: for val in mem_data["value"]: @@ -86,8 +89,6 @@ def update( # If Windows Enrollment Profile exists, continue if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value").get("id") # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update/Intune/update_windowsFeatureUpdates.py b/src/IntuneCD/update/Intune/update_windowsFeatureUpdates.py index d4f931ed..01adc4f7 100644 --- a/src/IntuneCD/update/Intune/update_windowsFeatureUpdates.py +++ b/src/IntuneCD/update/Intune/update_windowsFeatureUpdates.py @@ -78,6 +78,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + data = {"value": ""} if mem_data["value"]: for val in mem_data["value"]: @@ -88,8 +91,6 @@ def update( # If Windows Feature Update Profile exists, continue if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value").get("id") # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) diff --git a/src/IntuneCD/update/Intune/update_windowsQualityUpdates.py b/src/IntuneCD/update/Intune/update_windowsQualityUpdates.py index df5ee8d4..1176c713 100644 --- a/src/IntuneCD/update/Intune/update_windowsQualityUpdates.py +++ b/src/IntuneCD/update/Intune/update_windowsQualityUpdates.py @@ -78,6 +78,9 @@ def update( assign_obj = repo_data["assignments"] repo_data.pop("assignments", None) + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + data = {"value": ""} if mem_data["value"]: for val in mem_data["value"]: @@ -88,8 +91,6 @@ def update( # If Windows Quality Update Profile exists, continue if data["value"]: print("-" * 90) - if scope_tags: - repo_data = get_scope_tags_id(repo_data, scope_tags) mem_id = data.get("value").get("id") # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) From 1743865a50152460663485bb1aaf5b4ab6c20bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Thu, 29 Feb 2024 08:40:55 +0100 Subject: [PATCH 22/35] fix scope tag bug --- src/IntuneCD/backup/Intune/backup_notificationTemplate.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/IntuneCD/backup/Intune/backup_notificationTemplate.py b/src/IntuneCD/backup/Intune/backup_notificationTemplate.py index e1fb7970..30314ff9 100644 --- a/src/IntuneCD/backup/Intune/backup_notificationTemplate.py +++ b/src/IntuneCD/backup/Intune/backup_notificationTemplate.py @@ -31,7 +31,6 @@ def savebackup(path, output, token, prefix, append_id, audit, scope_tags): results = {"config_count": 0, "outputs": []} audit_data = None - scope_tags = None configpath = path + "/" + "Compliance Policies/Message Templates/" q_param = "?$expand=localizedNotificationMessages" data = makeapirequest(ENDPOINT, token, q_param) @@ -51,12 +50,12 @@ def savebackup(path, output, token, prefix, append_id, audit, scope_tags): q_param = "?$expand=localizedNotificationMessages" template_data = makeapirequest(ENDPOINT + "/" + template["id"], token, q_param) - graph_id = template_data["id"] - template_data = remove_keys(template_data) - if scope_tags: template_data = get_scope_tags_name(template_data, scope_tags) + graph_id = template_data["id"] + template_data = remove_keys(template_data) + for locale in template_data["localizedNotificationMessages"]: remove_keys(locale) From 067593bf26cd60dfb4553f234ac4a61c3ce29475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Thu, 29 Feb 2024 08:41:41 +0100 Subject: [PATCH 23/35] bump to 2.2.0.beta5 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 9b0a56f0..dac81630 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = IntuneCD -version = 2.2.0.beta4 +version = 2.2.0.beta5 author = Tobias Almén author_email = almenscorner@outlook.com description = Tool to backup and update configurations in Intune From 993ca480ecda31f1c364854cba6c3cd1a5b63366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:04:44 +0100 Subject: [PATCH 24/35] include resource type in commit --- src/IntuneCD/intunecdlib/process_audit_data.py | 2 +- tests/test_process_audit_data.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/IntuneCD/intunecdlib/process_audit_data.py b/src/IntuneCD/intunecdlib/process_audit_data.py index a7030f2b..9c33a0c5 100644 --- a/src/IntuneCD/intunecdlib/process_audit_data.py +++ b/src/IntuneCD/intunecdlib/process_audit_data.py @@ -147,7 +147,7 @@ def _git_commit_changes(audit_record, path, file): "commit", "-m", ( - f"{audit_record['activityOperationType']} by {audit_record['actor']}\n" + f"{audit_record['auditResourceType']} {audit_record['activityOperationType']} by {audit_record['actor']}\n" f"Date: {audit_record['activityDateTime']}\n" f"result: {audit_record['activityResult']}" ), diff --git a/tests/test_process_audit_data.py b/tests/test_process_audit_data.py index dc069f83..816bb9b0 100644 --- a/tests/test_process_audit_data.py +++ b/tests/test_process_audit_data.py @@ -26,6 +26,7 @@ def test_configure_git(self, mock_run): """ self.record = { "activityDateTime": "2021-05-25T20:00:00Z", + "activityResourceType": "test", "userPrincipalName": "test", "actor": "test", } @@ -84,6 +85,7 @@ def test_git_commit_changes(self, mock_run): mock_run.return_value.returncode = 0 self.record = { "activityDateTime": "2021-05-25T20:00:00Z", + "auditResourceType": "test", "userPrincipalName": "test", "actor": "test", "activityOperationType": "test", From a68b8fb39753b2d19b3f1897aabafbcdc0ff743c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:05:09 +0100 Subject: [PATCH 25/35] include scope tags for ESP --- src/IntuneCD/update_intune.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IntuneCD/update_intune.py b/src/IntuneCD/update_intune.py index b560cc8c..5eef9e95 100644 --- a/src/IntuneCD/update_intune.py +++ b/src/IntuneCD/update_intune.py @@ -98,7 +98,7 @@ def update_intune( from .update.Intune.update_enrollmentStatusPage import update diff_summary.append( - update(path, token, assignment, report, create_groups, remove) + update(path, token, assignment, report, create_groups, remove, scope_tags) ) if "EnrollmentConfigurations" not in exclude: From 13391d737575cce268413667e374ed817efcc3f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:05:44 +0100 Subject: [PATCH 26/35] pop additional keys --- .../update/Intune/update_conditionalAccess.py | 14 +++++++++++++- src/IntuneCD/update/Intune/update_roles.py | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/IntuneCD/update/Intune/update_conditionalAccess.py b/src/IntuneCD/update/Intune/update_conditionalAccess.py index e88993ec..64d414d5 100644 --- a/src/IntuneCD/update/Intune/update_conditionalAccess.py +++ b/src/IntuneCD/update/Intune/update_conditionalAccess.py @@ -49,7 +49,7 @@ def update(path, token, report, remove): # and set query parameter with open(file, encoding="utf-8") as f: repo_data = load_file(filename, f) - repo_data["conditions"].pop("users", None) + repo_data.get("conditions").pop("users", None) data = {"value": ""} if mem_data["value"]: @@ -74,6 +74,18 @@ def update(path, token, report, remove): # Remove keys before using DeepDiff data["value"] = remove_keys(data["value"]) + repo_data.pop("templateId", None) + data["value"].pop("templateId", None) + + if repo_data.get("grantControls").get("authenticationStrength"): + repo_data["grantControls"]["authenticationStrength"].pop( + "combinationConfigurations@odata.context", None + ) + if data.get("value").get("grantControls").get("authenticationStrength"): + data.get("value").get("grantControls").get( + "authenticationStrength" + ).pop("combinationConfigurations@odata.context", None) + diff = DeepDiff(data["value"], repo_data, ignore_order=True) # If any changed values are found, push them to Intune diff --git a/src/IntuneCD/update/Intune/update_roles.py b/src/IntuneCD/update/Intune/update_roles.py index d5c10479..df79f4dd 100644 --- a/src/IntuneCD/update/Intune/update_roles.py +++ b/src/IntuneCD/update/Intune/update_roles.py @@ -114,6 +114,7 @@ def update(path, token, report, remove=False, scope_tags=None): print("-" * 90) print("Role not found, creating role: " + repo_data["displayName"]) if report is False: + repo_data.pop("roleAssignments", None) request_json = json.dumps(repo_data) post_request = makeapirequestPost( ENDPOINT, From 8e8845938056fdaf4702d77cd8f54c0f744f823a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:06:16 +0100 Subject: [PATCH 27/35] bump to 2.2.0.beta6 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index dac81630..268dc7c6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = IntuneCD -version = 2.2.0.beta5 +version = 2.2.0.beta6 author = Tobias Almén author_email = almenscorner@outlook.com description = Tool to backup and update configurations in Intune From 7862ae651b2af88057e9eb4d2c67da49272b849e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Sun, 3 Mar 2024 12:25:58 +0100 Subject: [PATCH 28/35] add backup,update,remove of custom compliance and linux --- .../Intune/backup_compliancePolicies.py | 161 +++++++ .../backup/Intune/backup_complianceScripts.py | 99 +++++ .../Intune/backup_reusablePolicySettings.py | 101 +++++ src/IntuneCD/backup_intune.py | 23 + src/IntuneCD/document_intune.py | 11 + src/IntuneCD/run_backup.py | 13 +- src/IntuneCD/run_update.py | 4 +- .../update/Intune/update_compliance.py | 23 + .../Intune/update_compliancePolicies.py | 369 ++++++++++++++++ .../update/Intune/update_complianceScripts.py | 156 +++++++ .../Intune/update_reusablePolicySettings.py | 156 +++++++ src/IntuneCD/update_intune.py | 17 + .../Intune/test_backup_compliancePolicies.py | 321 ++++++++++++++ .../Intune/test_backup_complianceScript.py | 224 ++++++++++ .../test_backup_reusablePolicySettings.py | 249 +++++++++++ tests/Update/Intune/test_update_compliance.py | 51 +++ .../Intune/test_update_compliancePolicies.py | 397 ++++++++++++++++++ .../Intune/test_update_complianceScripts.py | 184 ++++++++ .../test_update_reusablePolicySettings.py | 176 ++++++++ 19 files changed, 2729 insertions(+), 6 deletions(-) create mode 100644 src/IntuneCD/backup/Intune/backup_compliancePolicies.py create mode 100644 src/IntuneCD/backup/Intune/backup_complianceScripts.py create mode 100644 src/IntuneCD/backup/Intune/backup_reusablePolicySettings.py create mode 100644 src/IntuneCD/update/Intune/update_compliancePolicies.py create mode 100644 src/IntuneCD/update/Intune/update_complianceScripts.py create mode 100644 src/IntuneCD/update/Intune/update_reusablePolicySettings.py create mode 100644 tests/Backup/Intune/test_backup_compliancePolicies.py create mode 100644 tests/Backup/Intune/test_backup_complianceScript.py create mode 100644 tests/Backup/Intune/test_backup_reusablePolicySettings.py create mode 100644 tests/Update/Intune/test_update_compliancePolicies.py create mode 100644 tests/Update/Intune/test_update_complianceScripts.py create mode 100644 tests/Update/Intune/test_update_reusablePolicySettings.py diff --git a/src/IntuneCD/backup/Intune/backup_compliancePolicies.py b/src/IntuneCD/backup/Intune/backup_compliancePolicies.py new file mode 100644 index 00000000..039a33d5 --- /dev/null +++ b/src/IntuneCD/backup/Intune/backup_compliancePolicies.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +This module backs up all Compliance Polices in Intune. +""" + +from ...intunecdlib.check_prefix import check_prefix_match +from ...intunecdlib.clean_filename import clean_filename +from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name +from ...intunecdlib.remove_keys import remove_keys +from ...intunecdlib.save_output import save_output + +# Set MS Graph endpoint +ENDPOINT = "https://graph.microsoft.com/beta/deviceManagement/compliancePolicies" + + +def _check_linux_discovery_script(data): + if isinstance(data, dict): + if "linux_customcompliance_discoveryscript" in data.values(): + return True + return any(_check_linux_discovery_script(v) for v in data.values()) + if isinstance(data, list): + return any(_check_linux_discovery_script(v) for v in data) + return False + + +def _get_detection_script_id(data, path=None): + if path is None: + path = [] + if isinstance(data, dict): + for k, v in data.items(): + if isinstance(v, dict): + new_path = _get_detection_script_id(v, path + [k]) + if new_path is not None: + return new_path + elif isinstance(v, list): + for i, item in enumerate(v): + new_path = _get_detection_script_id(item, path + [k, i]) + if new_path is not None: + return new_path + elif v == "linux_customcompliance_discoveryscript": + return path + return None + + +def _get_value_from_path(data, path): + for key in path: + if isinstance(data, list): + data = data[int(key)] + else: + data = data[key] + return data["simpleSettingValue"]["value"] + + +# Get all Compliance policies and save them in specified path +def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tags): + """ + Saves all Compliance policies in Intune to a JSON or YAML file. + + :param path: Path to save the backup to + :param output: Format the backup will be saved as + :param exclude: If "assignments" is in the list, it will not back up the assignments + :param token: Token to use for authenticating the request + """ + + results = {"config_count": 0, "outputs": []} + audit_data = None + configpath = path + "/" + "Compliance Policies/Policies/" + q_param = { + "$expand": "settings", + } + data = makeapirequest(ENDPOINT, token, q_param) + + assignment_responses = batch_assignment( + data, "deviceManagement/compliancePolicies/", "/assignments", token + ) + if audit: + graph_filter = "componentName eq 'DeviceCompliancePolicy'" + audit_data = makeAuditRequest(graph_filter, token) + + for policy in data["value"]: + if prefix and not check_prefix_match(policy["name"], prefix): + continue + + # Is the policy a Linux discovery script? + if _check_linux_discovery_script(policy): + # Get the detection script ID + detection_script_id_path = _get_detection_script_id(policy) + if detection_script_id_path is not None: + detection_script_id = _get_value_from_path( + policy, detection_script_id_path + ) + # get the script name + detection_script = makeapirequest( + "https://graph.microsoft.com/beta/deviceManagement/reusablePolicySettings/", + token, + {"$filter": f"id eq '{detection_script_id}'"}, + ) + if detection_script["value"]: + policy["detectionScriptName"] = detection_script["value"][0][ + "displayName" + ] + + # get scheduledActionsForRule + scheduledActionsForRule = makeapirequest( + f"{ENDPOINT}/{policy['id']}/scheduledActionsForRule", + token, + {"$expand": "scheduledActionConfigurations"}, + ) + + policy["scheduledActionsForRule"] = scheduledActionsForRule["value"] + + results["config_count"] += 1 + print("Backing up compliance policy: " + policy["name"]) + + if scope_tags: + policy = get_scope_tags_name(policy, scope_tags) + + if "assignments" not in exclude: + assignments = get_object_assignment(policy["id"], assignment_responses) + if assignments: + policy["assignments"] = assignments + + graph_id = policy["id"] + policy = remove_keys(policy) + for rule in policy["scheduledActionsForRule"]: + remove_keys(rule) + if policy["scheduledActionsForRule"]: + for scheduled_config in policy["scheduledActionsForRule"][0][ + "scheduledActionConfigurations" + ]: + remove_keys(scheduled_config) + + # Get filename without illegal characters + fname = clean_filename(policy["name"]) + if append_id: + fname = f"{fname}_{policy['technologies']}__{graph_id}" + else: + fname = f"{fname}_{policy['technologies']}" + # Save Compliance policy as JSON or YAML depending on configured value + # in "-o" + save_output( + output, + configpath, + fname, + policy, + ) + + results["outputs"].append(fname) + + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" + ) + + return results diff --git a/src/IntuneCD/backup/Intune/backup_complianceScripts.py b/src/IntuneCD/backup/Intune/backup_complianceScripts.py new file mode 100644 index 00000000..c544effb --- /dev/null +++ b/src/IntuneCD/backup/Intune/backup_complianceScripts.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +This module backs up all Compliance scripts in Intune. +""" + +import base64 +import os + +from ...intunecdlib.check_prefix import check_prefix_match +from ...intunecdlib.clean_filename import clean_filename +from ...intunecdlib.graph_batch import batch_request +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name +from ...intunecdlib.remove_keys import remove_keys +from ...intunecdlib.save_output import save_output + +# Set MS Graph endpoint +ENDPOINT = "https://graph.microsoft.com/beta/deviceManagement/deviceComplianceScripts/" + + +# Get all Compliance scripts and save them in specified path +def savebackup(path, output, token, prefix, append_id, audit, scope_tags): + """ + Saves all Compliance scripts in Intune to a JSON or YAML file and script files. + + :param path: Path to save the backup to + :param output: Format the backup will be saved as + :param exclude: If "assignments" is in the list, it will not back up the assignments + :param token: Token to use for authenticating the request + """ + + results = {"config_count": 0, "outputs": []} + audit_data = None + configpath = path + "/" + "Compliance Policies/Scripts/" + data = makeapirequest(ENDPOINT, token) + if data["value"]: + script_ids = [] + for script in data["value"]: + script_ids.append(script["id"]) + + script_data_responses = batch_request( + script_ids, "deviceManagement/deviceComplianceScripts/", "", token + ) + if audit: + graph_filter = "componentName eq 'DeviceConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) + + for script_data in script_data_responses: + if prefix and not check_prefix_match(script_data["displayName"], prefix): + continue + + results["config_count"] += 1 + + if scope_tags: + script_data = get_scope_tags_name(script_data, scope_tags) + + graph_id = script_data["id"] + script_data = remove_keys(script_data) + + print("Backing up Compliance script: " + script_data["displayName"]) + + # Get filename without illegal characters + fname = clean_filename(script_data["displayName"]) + + script_file_name = script_data["displayName"] + if append_id: + fname = f"{fname}__{graph_id}" + script_name = script_data["displayName"].replace(".ps1", "") + script_file_name = f"{script_name}__{graph_id}.ps1" + # Save Compliance script as JSON or YAML depending on configured value + # in "-o" + save_output(output, configpath, fname, script_data) + + results["outputs"].append(fname) + + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" + ) + + # Save Compliance script data to the script data folder + if script_data.get("detectionScriptContent"): + if not os.path.exists(configpath + "Script Data/"): + os.makedirs(configpath + "Script Data/") + decoded = base64.b64decode( + script_data["detectionScriptContent"] + ).decode("utf-8") + f = open( + configpath + "Script Data/" + script_file_name, + "w", + encoding="utf-8", + ) + f.write(decoded) + + return results diff --git a/src/IntuneCD/backup/Intune/backup_reusablePolicySettings.py b/src/IntuneCD/backup/Intune/backup_reusablePolicySettings.py new file mode 100644 index 00000000..7015e322 --- /dev/null +++ b/src/IntuneCD/backup/Intune/backup_reusablePolicySettings.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +This module backs up all Compliance scripts in Intune. +""" + +import base64 +import os + +from ...intunecdlib.check_prefix import check_prefix_match +from ...intunecdlib.clean_filename import clean_filename +from ...intunecdlib.graph_request import makeapirequest, makeAuditRequest +from ...intunecdlib.process_audit_data import process_audit_data +from ...intunecdlib.process_scope_tags import get_scope_tags_name +from ...intunecdlib.remove_keys import remove_keys +from ...intunecdlib.save_output import save_output + +# Set MS Graph endpoint +ENDPOINT = "https://graph.microsoft.com/beta/deviceManagement/reusablePolicySettings/" + + +# Get all Compliance scripts and save them in specified path +def savebackup(path, output, token, prefix, append_id, audit, scope_tags): + """ + Saves all Compliance scripts in Intune to a JSON or YAML file and script files. + + :param path: Path to save the backup to + :param output: Format the backup will be saved as + :param exclude: If "assignments" is in the list, it will not back up the assignments + :param token: Token to use for authenticating the request + """ + + results = {"config_count": 0, "outputs": []} + audit_data = None + configpath = path + "/" + "Compliance Policies/Scripts/" + data = makeapirequest(ENDPOINT, token) + if data["value"]: + if audit: + graph_filter = "componentName eq 'DeviceConfiguration'" + audit_data = makeAuditRequest(graph_filter, token) + for policy in data["value"]: + q_param = { + "$select": "id,settinginstance,displayname,description,settingDefinitionId,version" + } + policy = makeapirequest(f"{ENDPOINT}/{policy['id']}", token, q_param) + + if ( + policy.get("settingDefinitionId") + != "linux_customcompliance_discoveryscript_reusablesetting" + ): + continue + + if prefix and not check_prefix_match(policy["displayName"], prefix): + continue + + results["config_count"] += 1 + + if scope_tags: + script_data = get_scope_tags_name(policy, scope_tags) + + graph_id = policy["id"] + script_data = remove_keys(policy) + + print("Backing up Reusable policy setting: " + policy["displayName"]) + + # Get filename without illegal characters + fname = clean_filename(policy["displayName"]) + + script_file_name = script_data["displayName"] + if append_id: + fname = f"{fname}__{graph_id}" + script_name = policy["displayName"].replace(".sh", "") + script_file_name = f"{script_name}__{graph_id}.sh" + # Save Compliance script as JSON or YAML depending on configured value + # in "-o" + save_output(output, configpath, fname, script_data) + + results["outputs"].append(fname) + + if audit_data: + compare_data = {"type": "resourceId", "value": graph_id} + process_audit_data( + audit_data, compare_data, path, f"{configpath}{fname}.{output}" + ) + + # Save Compliance script data to the script data folder + if script_data.get("settingInstance").get("simpleSettingValue"): + if not os.path.exists(configpath + "Script Data/"): + os.makedirs(configpath + "Script Data/") + decoded = base64.b64decode( + script_data["settingInstance"]["simpleSettingValue"]["value"] + ).decode("utf-8") + f = open( + configpath + "Script Data/" + script_file_name, + "w", + encoding="utf-8", + ) + f.write(decoded) + + return results diff --git a/src/IntuneCD/backup_intune.py b/src/IntuneCD/backup_intune.py index 98746691..a185e913 100644 --- a/src/IntuneCD/backup_intune.py +++ b/src/IntuneCD/backup_intune.py @@ -55,6 +55,29 @@ def backup_intune(results, path, output, exclude, token, prefix, append_id, args savebackup(path, output, exclude, token, append_id, args.audit, scope_tags) ) + if "DeviceCompliancePolicies" not in exclude: + from .backup.Intune.backup_compliancePolicies import savebackup + + results.append( + savebackup( + path, output, exclude, token, prefix, append_id, args.audit, scope_tags + ) + ) + + if "ReusablePolicySettings" not in exclude: + from .backup.Intune.backup_reusablePolicySettings import savebackup + + results.append( + savebackup(path, output, token, prefix, append_id, args.audit, scope_tags) + ) + + if "ComplianceScripts" not in exclude: + from .backup.Intune.backup_complianceScripts import savebackup + + results.append( + savebackup(path, output, token, prefix, append_id, args.audit, scope_tags) + ) + if "Compliance" not in exclude: from .backup.Intune.backup_compliance import savebackup diff --git a/src/IntuneCD/document_intune.py b/src/IntuneCD/document_intune.py index 8944cf37..f75fa137 100644 --- a/src/IntuneCD/document_intune.py +++ b/src/IntuneCD/document_intune.py @@ -131,6 +131,17 @@ def document_intune(configpath, outpath, maxlength, split, cleanup, decode): decode, ) + # Document Compliance Scripts + document_configs( + f"{configpath}/Compliance Policies/Scripts", + outpath, + "Compliance Scripts", + maxlength, + split, + cleanup, + decode, + ) + # Message Templates document_configs( f"{configpath}/Compliance Policies/Message Templates", diff --git a/src/IntuneCD/run_backup.py b/src/IntuneCD/run_backup.py index ffc4e12b..ed5401d4 100644 --- a/src/IntuneCD/run_backup.py +++ b/src/IntuneCD/run_backup.py @@ -121,6 +121,14 @@ def start(): "windowsDriverUpdates", "windowsFeatuteUpdates", "windowsQualityUpdates", + "Roles", + "ScopeTags", + "VPPusedLicenseCount", + "GPlaySyncTime", + "CompliancePartnerHeartbeat", + "DeviceCompliancePolicy", + "ComplianceScripts", + "ReusablePolicySettings", "entraApplications", "entraAuthenticationFlowsPolicy", "entraAuthenticationMethods", @@ -134,11 +142,6 @@ def start(): "entraSSPR", "entraUserSettings", "entraDomains", - "Roles", - "ScopeTags", - "VPPusedLicenseCount", - "GPlaySyncTime", - "CompliancePartnerHeartbeat", ], nargs="+", ) diff --git a/src/IntuneCD/run_update.py b/src/IntuneCD/run_update.py index 6d984317..f4477be4 100644 --- a/src/IntuneCD/run_update.py +++ b/src/IntuneCD/run_update.py @@ -110,7 +110,9 @@ def start(): "DeviceCategories", "Roles", "ScopeTags", - "entraAuthenticationFlowsPolicy", + "DeviceCompliancePolicy", + "ComplianceScripts", + "ReusablePolicySettings" "entraAuthenticationFlowsPolicy", "entraAuthenticationMethods", "entraAuthorizationPolicy", "entraB2BPolicy", diff --git a/src/IntuneCD/update/Intune/update_compliance.py b/src/IntuneCD/update/Intune/update_compliance.py index c1a76e45..ac0c0447 100644 --- a/src/IntuneCD/update/Intune/update_compliance.py +++ b/src/IntuneCD/update/Intune/update_compliance.py @@ -28,6 +28,20 @@ ENDPOINT = "https://graph.microsoft.com/beta/deviceManagement/deviceCompliancePolicies" +def _set_compliance_script_id(data, token): + compliance_script_id = makeapirequest( + "https://graph.microsoft.com/beta/deviceManagement/deviceComplianceScripts", + token, + {"$filter": f"displayName eq '{data['deviceComplianceScriptName']}'"}, + ) + if compliance_script_id.get("value"): + data["deviceCompliancePolicyScript"][ + "deviceComplianceScriptId" + ] = compliance_script_id["value"][0]["id"] + + return data + + def update( path, token, @@ -73,6 +87,9 @@ def update( with open(file, encoding="utf-8") as f: repo_data = load_file(filename, f) + if repo_data.get("platforms") == "linux": + continue + # Create object to pass in to assignment function assign_obj = {} if "assignments" in repo_data: @@ -108,6 +125,9 @@ def update( ): remove_keys(scheduled_config) + if repo_data.get("deviceComplianceScriptName"): + repo_data = _set_compliance_script_id(repo_data, token) + diff = DeepDiff( data["value"], repo_data, @@ -200,6 +220,9 @@ def update( + repo_data["displayName"] ) if report is False: + if repo_data.get("deviceComplianceScriptName"): + repo_data = _set_compliance_script_id(repo_data, token) + request_json = json.dumps(repo_data) post_request = makeapirequestPost( ENDPOINT, diff --git a/src/IntuneCD/update/Intune/update_compliancePolicies.py b/src/IntuneCD/update/Intune/update_compliancePolicies.py new file mode 100644 index 00000000..97c935bc --- /dev/null +++ b/src/IntuneCD/update/Intune/update_compliancePolicies.py @@ -0,0 +1,369 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +This module is used to update all Compliance Policies in Intune. +""" + +import json +import os + +from deepdiff import DeepDiff + +from ...intunecdlib.check_file import check_file +from ...intunecdlib.diff_summary import DiffSummary +from ...intunecdlib.graph_batch import batch_assignment, get_object_assignment +from ...intunecdlib.graph_request import ( + makeapirequest, + makeapirequestDelete, + makeapirequestPatch, + makeapirequestPost, + makeapirequestPut, +) +from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id +from ...intunecdlib.remove_keys import remove_keys +from .update_assignment import post_assignment_update, update_assignment + +# Set MS Graph endpoint +ENDPOINT = "https://graph.microsoft.com/beta/deviceManagement/compliancePolicies" + + +def _remove_keys(data): + if isinstance(data, dict): + return { + k: _remove_keys(v) + for k, v in data.items() + if k + not in [ + "settingValueTemplateReference", + "settingInstanceTemplateReference", + "note", + "settingCount", + "creationSource", + "settings@odata.context", + "detectionScriptName", + ] + } + if isinstance(data, list): + return [_remove_keys(v) for v in data] + + return data + + +def _get_detection_script_id_path(data, path=None): + if path is None: + path = [] + if isinstance(data, dict): + for k, v in data.items(): + if isinstance(v, dict): + new_path = _get_detection_script_id_path(v, path + [k]) + if new_path is not None: + return new_path + elif isinstance(v, list): + for i, item in enumerate(v): + new_path = _get_detection_script_id_path(item, path + [k, i]) + if new_path is not None: + return new_path + elif v == "linux_customcompliance_discoveryscript": + return path + return None + + +def _set_value_from_path(data, value, path): + item = data + for key in path[:-1]: + if isinstance(item, list): + item = item[int(key)] + else: + item = item[key] + if isinstance(item, list): + item[int(path[-1])] = value + else: + item[path[-1]] = value + return data + + +def _set_detection_script_id(data, token): + # get detection script id + script_id = makeapirequest( + "https://graph.microsoft.com/beta/deviceManagement/reusablePolicySettings/", + token, + {"$filter": f"displayName eq '{data['detectionScriptName']}'"}, + ) + if script_id.get("value"): + script_id_path = _get_detection_script_id_path(data) + script_id_path = script_id_path + ["simpleSettingValue", "value"] + data = _set_value_from_path(data, script_id["value"][0]["id"], script_id_path) + + return data + + +def update( + path, + token, + assignment=False, + report=False, + create_groups=False, + remove=False, + scope_tags=None, +): + """ + This function updates all Compliance Polices in Intune, + if the configuration in Intune differs from the JSON/YAML file. + + :param path: Path to where the backup is saved + :param token: Token to use for authenticating the request + :param assignment: Boolean to determine if assignments should be updated + """ + + # Set Compliance Policy path + configpath = path + "/" + "Compliance Policies/Policies/" + diff_summary = [] + # If App Configuration path exists, continue + if os.path.exists(configpath): + # Get compliance policies + q_param = {"$expand": "settings"} + mem_data = makeapirequest(ENDPOINT, token, q_param) + # Get current assignments + mem_assignments = batch_assignment( + mem_data, + "deviceManagement/compliancePolicies/", + "/assignments", + token, + ) + + for filename in os.listdir(configpath): + file = check_file(configpath, filename) + if file is False: + continue + # Check which format the file is saved as then open file, load data + # and set query parameter + with open(file, encoding="utf-8") as f: + repo_data = load_file(filename, f) + + # continue to next file if not "technologies" in repo_data + if "technologies" not in repo_data: + continue + + # Create object to pass in to assignment function + assign_obj = {} + if "assignments" in repo_data: + assign_obj = repo_data["assignments"] + repo_data.pop("assignments", None) + + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + + # If Compliance Policy exists, continue + data = {"value": ""} + if mem_data["value"]: + for val in mem_data["value"]: + if ( + repo_data["technologies"] == val["technologies"] + and repo_data["name"] == val["name"] + ): + data["value"] = val + mem_data["value"].remove(val) + + if data["value"]: + print("-" * 90) + mem_id = data.get("value", {}).get("id", None) + data["value"] = remove_keys(data["value"]) + + scheduledActionsForRule = makeapirequest( + f"{ENDPOINT}/{mem_id}/scheduledActionsForRule", + token, + {"$expand": "scheduledActionConfigurations"}, + ) + + data.get("value")["scheduledActionsForRule"] = scheduledActionsForRule[ + "value" + ] + + if data.get("value", {}).get("scheduledActionsForRule"): + for rule in data.get("value").get("scheduledActionsForRule"): + remove_keys(rule) + for scheduled_config in ( + data.get("value") + .get("scheduledActionsForRule", [])[0] + .get("scheduledActionConfigurations", []) + ): + remove_keys(scheduled_config) + + diff = DeepDiff( + data["value"], + repo_data, + ignore_order=True, + exclude_paths=[ + "root['scheduledActionsForRule'][0]['scheduledActionConfigurations']", + "root['settings']", + "root['settings@odata.context']", + ], + ).get("values_changed", {}) + + # If any changed values are found, push them to Intune + if diff and report is False: + if repo_data.get("detectionScriptName"): + repo_data = _set_detection_script_id(repo_data, token) + scheduled_actions = repo_data["scheduledActionsForRule"] + repo_data.pop("scheduledActionsForRule", None) + request_data = json.dumps(repo_data) + q_param = None + makeapirequestPatch( + ENDPOINT + "/" + mem_id, + token, + q_param, + request_data, + status_code=204, + ) + repo_data["scheduledActionsForRule"] = scheduled_actions + + diff_policy = DiffSummary( + data=diff, + name=repo_data["name"], + type="Compliance Policy", + ) + + diff_summary.append(diff_policy) + + if repo_data["scheduledActionsForRule"]: + rdiff = None + for mem_rule, repo_rule in zip( + data.get("value").get("scheduledActionsForRule"), + repo_data["scheduledActionsForRule"], + ): + rdiff = DeepDiff(mem_rule, repo_rule, ignore_order=True).get( + "values_changed", {} + ) + + if rdiff and report is False: + request_data = { + "scheduledActions": repo_data["scheduledActionsForRule"] + } + + request_json = json.dumps(request_data) + q_param = None + makeapirequestPost( + f"{ENDPOINT}/{mem_id}/setScheduledActions/", + token, + q_param, + request_json, + ) + + rdiff_summary = DiffSummary( + data=rdiff, + name="", + type="Compliance Policy Rules", + ) + + diff_policy.diffs += rdiff_summary.diffs + diff_policy.count += rdiff_summary.count + + if repo_data.get("settings"): + for repo_setting, mem_setting in zip( + repo_data.get("settings"), data["value"].get("settings") + ): + if ( + "custom" + not in repo_setting["settingInstance"][ + "settingDefinitionId" + ] + ): + sdiff = DeepDiff( + mem_setting, repo_setting, ignore_order=True + ).get("values_changed", {}) + + if sdiff and report is False: + request_json = json.dumps(repo_data) + q_param = None + makeapirequestPut( + f"{ENDPOINT}/{mem_id}", + token, + q_param, + request_json, + status_code=204, + ) + + sdiff_summary = DiffSummary( + data=sdiff, + name="", + type="Compliance Policy Settings", + ) + + diff_policy.diffs += sdiff_summary.diffs + diff_policy.count += sdiff_summary.count + + if assignment: + mem_assign_obj = get_object_assignment(mem_id, mem_assignments) + assignment_update = update_assignment( + assign_obj, mem_assign_obj, token, create_groups + ) + if assignment_update is not None: + request_data = {"assignments": assignment_update} + post_assignment_update( + request_data, + mem_id, + "deviceManagement/compliancePolicies", + "assign", + token, + ) + + # If Compliance Policy does not exist, create it and assign + else: + print("-" * 90) + print( + "Compliance Policy not found, creating Policy: " + repo_data["name"] + ) + if report is False: + if repo_data.get("detectionScriptName"): + repo_data = _set_detection_script_id(repo_data, token) + repo_data = _remove_keys(repo_data) + request_json = json.dumps(repo_data) + post_request = makeapirequestPost( + ENDPOINT, + token, + q_param=None, + jdata=request_json, + status_code=201, + ) + mem_assign_obj = [] + assignment = update_assignment( + assign_obj, mem_assign_obj, token, create_groups + ) + + request_data = { + "scheduledActions": repo_data["scheduledActionsForRule"] + } + + request_json = json.dumps(request_data) + q_param = None + makeapirequestPost( + f"{ENDPOINT}/{post_request['id']}/setScheduledActions/", + token, + q_param, + request_json, + ) + + if assignment is not None: + request_data = {"assignments": assignment} + post_assignment_update( + request_data, + post_request["id"], + "deviceManagement/compliancePolicies", + "assign", + token, + ) + print("Compliance Policy created with id: " + post_request["id"]) + + # If any Compliance Policies are left in mem_data, remove them from Intune as they are not in the repo + if mem_data.get("value", None) is not None and remove is True: + for val in mem_data["value"]: + print("-" * 90) + print("Removing Compliance Policy from Intune: " + val["name"]) + if report is False: + makeapirequestDelete( + f"{ENDPOINT}/{val['id']}", token, status_code=200 + ) + + return diff_summary diff --git a/src/IntuneCD/update/Intune/update_complianceScripts.py b/src/IntuneCD/update/Intune/update_complianceScripts.py new file mode 100644 index 00000000..cef2f505 --- /dev/null +++ b/src/IntuneCD/update/Intune/update_complianceScripts.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +This module is used to update all Compliance Scripts in Intune. +""" + +import json +import os +import time + +from deepdiff import DeepDiff + +from ...intunecdlib.check_file import check_file +from ...intunecdlib.diff_summary import DiffSummary +from ...intunecdlib.graph_request import ( + makeapirequest, + makeapirequestDelete, + makeapirequestPatch, + makeapirequestPost, +) +from ...intunecdlib.load_file import load_file +from ...intunecdlib.process_scope_tags import get_scope_tags_id +from ...intunecdlib.remove_keys import remove_keys + +# Set MS Graph endpoint +ENDPOINT = "https://graph.microsoft.com/beta/deviceManagement/deviceComplianceScripts" + + +def update( + path, + token, + report=False, + remove=False, + scope_tags=None, +): + """ + This function updates all Compliance scripts in Intune if the configuration in Intune differs from the JSON/YAML file. + + :param path: Path to where the backup is saved + :param token: Token to use for authenticating the request + :param assignment: Boolean to determine if assignments should be updated + """ + + diff_summary = [] + # Set Compliance script path + configpath = path + "/" + "Compliance Policies/Scripts/" + # If Compliance script path exists, continue + if os.path.exists(configpath): + # Get scripts + mem_ComplianceScript = makeapirequest(ENDPOINT, token) + + for filename in os.listdir(configpath): + file = check_file(configpath, filename) + if file is False: + continue + # Check which format the file is saved as then open file, load data + # and set query parameter + with open(file, encoding="utf-8") as f: + repo_data = load_file(filename, f) + + if repo_data.get("settingDefinitionId"): + continue + + if scope_tags: + repo_data = get_scope_tags_id(repo_data, scope_tags) + + data = {"value": ""} + if mem_ComplianceScript["value"]: + for val in mem_ComplianceScript["value"]: + if repo_data["displayName"] == val["displayName"]: + data["value"] = val + mem_ComplianceScript["value"].remove(val) + + # If Compliance script exists, continue + if data["value"]: + print("-" * 90) + q_param = None + # Get Compliance script details + mem_data = makeapirequest( + ENDPOINT + "/" + data.get("value").get("id"), token + ) + mem_id = mem_data["id"] + # Remove keys before using DeepDiff + mem_data = remove_keys(mem_data) + + pdiff = DeepDiff( + mem_data["detectionScriptContent"], + repo_data["detectionScriptContent"], + ignore_order=True, + ).get("values_changed", {}) + + cdiff = DeepDiff( + mem_data, + repo_data, + ignore_order=True, + exclude_paths="root['detectionScriptContent']", + ).get("values_changed", {}) + + # If any changed values are found, push them to Intune + if pdiff or cdiff and report is False: + request_data = json.dumps(repo_data) + q_param = None + makeapirequestPatch( + ENDPOINT + "/" + mem_id, token, q_param, request_data + ) + + diff_config = DiffSummary( + data=cdiff, + name=repo_data["displayName"], + type="Compliance Script", + ) + + diff_script = DiffSummary( + data=pdiff, + name="", + type="Compliance Script", + message="Script changed, check commit history for details", + notify=False, + ) + + diff_config.diffs += diff_script.diffs + diff_config.count += diff_script.count + + diff_summary.append(diff_config) + + # If Compliance script does not exist, create it and assign + else: + print("-" * 90) + print( + "Compliance script not found, creating compliance script: " + + repo_data["displayName"] + ) + if report is False: + request_json = json.dumps(repo_data) + post_request = makeapirequestPost( + ENDPOINT, + token, + q_param=None, + jdata=request_json, + status_code=201, + ) + time.sleep(10) + print("Compliance script created with id: " + post_request["id"]) + + # If any Compliance Scripts are left in mem_ComplianceScript, remove them from Intune as they are not in the repo + if mem_ComplianceScript.get("value", None) is not None and remove is True: + for val in mem_ComplianceScript["value"]: + print("-" * 90) + print("Removing Compliance Script from Intune: " + val["displayName"]) + if report is False: + makeapirequestDelete( + f"{ENDPOINT}/{val['id']}", token, status_code=200 + ) + + return diff_summary diff --git a/src/IntuneCD/update/Intune/update_reusablePolicySettings.py b/src/IntuneCD/update/Intune/update_reusablePolicySettings.py new file mode 100644 index 00000000..7ae454a0 --- /dev/null +++ b/src/IntuneCD/update/Intune/update_reusablePolicySettings.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +This module is used to update all Compliance Scripts in Intune. +""" + +import json +import os + +from deepdiff import DeepDiff + +from ...intunecdlib.check_file import check_file +from ...intunecdlib.diff_summary import DiffSummary +from ...intunecdlib.graph_request import ( + makeapirequest, + makeapirequestDelete, + makeapirequestPost, + makeapirequestPut, +) +from ...intunecdlib.load_file import load_file +from ...intunecdlib.remove_keys import remove_keys + +# Set MS Graph endpoint +ENDPOINT = "https://graph.microsoft.com/beta/deviceManagement/reusablePolicySettings/" + + +def update( + path, + token, + report=False, + remove=False, +): + """ + This function updates all Compliance scripts in Intune if the configuration in Intune differs from the JSON/YAML file. + + :param path: Path to where the backup is saved + :param token: Token to use for authenticating the request + :param assignment: Boolean to determine if assignments should be updated + """ + + diff_summary = [] + # Set Compliance script path + configpath = path + "/" + "Compliance Policies/Scripts/" + # If Compliance script path exists, continue + if os.path.exists(configpath): + # Get scripts + mem_ComplianceScript = makeapirequest(ENDPOINT, token) + for filename in os.listdir(configpath): + file = check_file(configpath, filename) + if file is False: + continue + # Check which format the file is saved as then open file, load data + # and set query parameter + with open(file, encoding="utf-8") as f: + repo_data = load_file(filename, f) + + if not repo_data.get("settingDefinitionId"): + continue + + data = {"value": ""} + if mem_ComplianceScript["value"]: + for val in mem_ComplianceScript["value"]: + if repo_data["displayName"] == val["displayName"]: + data["value"] = val + mem_ComplianceScript["value"].remove(val) + + # If Compliance script exists, continue + if data["value"]: + print("-" * 90) + q_param = None + # Get Compliance script details + q_param = { + "$select": "id,settinginstance,displayname,description,settingDefinitionId,version" + } + mem_data = makeapirequest( + ENDPOINT + "/" + data.get("value").get("id"), token, q_param + ) + mem_id = mem_data["id"] + # Remove keys before using DeepDiff + mem_data = remove_keys(mem_data) + + pdiff = DeepDiff( + mem_data["settingInstance"]["simpleSettingValue"]["value"], + repo_data["settingInstance"]["simpleSettingValue"]["value"], + ignore_order=True, + ).get("values_changed", {}) + + cdiff = DeepDiff( + mem_data, + repo_data, + ignore_order=True, + exclude_paths="root['settingInstance']['simpleSettingValue']['value']", + ).get("values_changed", {}) + + # If any changed values are found, push them to Intune + if pdiff or cdiff and report is False: + request_data = json.dumps(repo_data) + q_param = None + makeapirequestPut( + ENDPOINT + "/" + mem_id, + token, + q_param, + request_data, + status_code=204, + ) + + diff_config = DiffSummary( + data=cdiff, + name=repo_data["displayName"], + type="Compliance Script", + ) + + diff_script = DiffSummary( + data=pdiff, + name="", + type="Compliance Script", + message="Script changed, check commit history for details", + notify=False, + ) + + diff_config.diffs += diff_script.diffs + diff_config.count += diff_script.count + + diff_summary.append(diff_config) + + # If Compliance script does not exist, create it and assign + else: + print("-" * 90) + print( + "Compliance script not found, creating compliance script: " + + repo_data["displayName"] + ) + if report is False: + request_json = json.dumps(repo_data) + post_request = makeapirequestPost( + ENDPOINT, + token, + q_param=None, + jdata=request_json, + status_code=201, + ) + + print("Compliance script created with id: " + post_request["id"]) + + # If any Compliance Scripts are left in mem_ComplianceScript, remove them from Intune as they are not in the repo + if mem_ComplianceScript.get("value", None) is not None and remove is True: + for val in mem_ComplianceScript["value"]: + print("-" * 90) + print("Removing Compliance Script from Intune: " + val["displayName"]) + if report is False: + makeapirequestDelete( + f"{ENDPOINT}/{val['id']}", token, status_code=200 + ) + + return diff_summary diff --git a/src/IntuneCD/update_intune.py b/src/IntuneCD/update_intune.py index 5eef9e95..544a4db5 100644 --- a/src/IntuneCD/update_intune.py +++ b/src/IntuneCD/update_intune.py @@ -41,6 +41,23 @@ def update_intune( update(path, token, assignment, report, create_groups, remove, scope_tags) ) + if "ReusablePolicySettings" not in exclude: + from .update.Intune.update_reusablePolicySettings import update + + diff_summary.append(update(path, token, report, remove)) + + if "ComplianceScripts" not in exclude: + from .update.Intune.update_complianceScripts import update + + diff_summary.append(update(path, token, report, remove, scope_tags)) + + if "DeviceCompliancePolicies" not in exclude: + from .update.Intune.update_compliancePolicies import update + + diff_summary.append( + update(path, token, assignment, report, create_groups, remove, scope_tags) + ) + if "Compliance" not in exclude: from .update.Intune.update_compliance import update diff --git a/tests/Backup/Intune/test_backup_compliancePolicies.py b/tests/Backup/Intune/test_backup_compliancePolicies.py new file mode 100644 index 00000000..49614978 --- /dev/null +++ b/tests/Backup/Intune/test_backup_compliancePolicies.py @@ -0,0 +1,321 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +"""This module tests backing up compliance.""" + +import json +import os.path +import unittest +from pathlib import Path +from unittest.mock import patch + +import yaml +from testfixtures import TempDirectory + +from src.IntuneCD.backup.Intune.backup_compliancePolicies import savebackup + +BATCH_ASSIGNMENT = [{"value": [{"id": "0", "target": {"groupName": "Group1"}}]}] +OBJECT_ASSIGNMENT = [{"target": {"groupName": "Group1"}}] + + +class TestBackupCompliance(unittest.TestCase): + """Test class for backup_compliance.""" + + def setUp(self): + self.directory = TempDirectory() + self.directory.create() + self.token = "token" + self.exclude = [] + self.append_id = False + self.saved_path = ( + f"{self.directory.path}/Compliance Policies/Policies/test_linuxMdm." + ) + self.expected_data = { + "roleScopeTagIds": ["0"], + "description": "Description value", + "name": "test", + "technologies": "linuxMdm", + "detectionScriptName": "test", + "settings": [ + { + "id": "0", + "settingInstance": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance", + "settingDefinitionId": "linux_customcompliance_required", + "settingInstanceTemplateReference": None, + "choiceSettingValue": { + "settingValueTemplateReference": None, + "value": "linux_customcompliance_required_true", + "children": [ + { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance", + "settingDefinitionId": "linux_customcompliance_discoveryscript", + "settingInstanceTemplateReference": None, + "simpleSettingValue": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationReferenceSettingValue", + "settingValueTemplateReference": None, + "value": "ea75ed9d-2df4-4977-8eb7-340c837ed5ee", + "note": None, + }, + } + ], + }, + }, + } + ], + "scheduledActionsForRule": [ + { + "ruleName": None, + "scheduledActionConfigurations": [{"gracePeriodHours": 0}], + } + ], + "assignments": [{"target": {"groupName": "Group1"}}], + } + self.compliance_policy = { + "value": [ + { + "roleScopeTagIds": ["0"], + "description": "Description value", + "name": "test", + "id": "0", + "technologies": "linuxMdm", + "settings": [ + { + "id": "0", + "settingInstance": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance", + "settingDefinitionId": "linux_customcompliance_required", + "settingInstanceTemplateReference": None, + "choiceSettingValue": { + "settingValueTemplateReference": None, + "value": "linux_customcompliance_required_true", + "children": [ + { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance", + "settingDefinitionId": "linux_customcompliance_discoveryscript", + "settingInstanceTemplateReference": None, + "simpleSettingValue": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationReferenceSettingValue", + "settingValueTemplateReference": None, + "value": "ea75ed9d-2df4-4977-8eb7-340c837ed5ee", + "note": None, + }, + } + ], + }, + }, + } + ], + "scheduledActionsForRule": [ + { + "ruleName": None, + "scheduledActionConfigurations": [{"gracePeriodHours": 0}], + } + ], + "assignments": [{"target": {"groupName": "Group1"}}], + } + ] + } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } + self.scheduled_actions = { + "value": [ + { + "ruleName": None, + "scheduledActionConfigurations": [{"gracePeriodHours": 0}], + } + ] + } + self.batch_assignment_patch = patch( + "src.IntuneCD.backup.Intune.backup_compliancePolicies.batch_assignment" + ) + self.batch_assignment = self.batch_assignment_patch.start() + self.batch_assignment.return_value = BATCH_ASSIGNMENT + + self.object_assignment_patch = patch( + "src.IntuneCD.backup.Intune.backup_compliancePolicies.get_object_assignment" + ) + self.object_assignment = self.object_assignment_patch.start() + self.object_assignment.return_value = OBJECT_ASSIGNMENT + + self.makeapirequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_compliancePolicies.makeapirequest" + ) + self.makeapirequest = self.makeapirequest_patch.start() + self.makeapirequest.side_effect = [ + self.compliance_policy, + {"value": [{"id": 0, "displayName": "test"}]}, + self.scheduled_actions, + ] + + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_compliancePolicies.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + + def tearDown(self): + self.directory.cleanup() + self.batch_assignment.stop() + self.object_assignment.stop() + self.makeapirequest.stop() + self.makeAuditRequest.stop() + + def test_backup_yml(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + output = "yaml" + count = savebackup( + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, + None, + ) + + with open(self.saved_path + output, "r", encoding="utf-8") as f: + data = json.dumps(yaml.safe_load(f)) + saved_data = json.loads(data) + + self.assertTrue( + Path(f"{self.directory.path}/Compliance Policies/Policies").exists() + ) + self.assertEqual(self.expected_data, saved_data) + self.assertEqual(1, count["config_count"]) + + def test_backup_json(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + output = "json" + count = savebackup( + self.directory.path, + output, + self.exclude, + self.token, + "", + self.append_id, + False, + None, + ) + + with open(self.saved_path + output, "r", encoding="utf-8") as f: + saved_data = json.load(f) + + self.assertTrue( + Path(f"{self.directory.path}/Compliance Policies/Policies").exists() + ) + self.assertEqual(self.expected_data, saved_data) + self.assertEqual(1, count["config_count"]) + + def test_backup_with_no_returned_data(self): + """The count should be 0 if no data is returned.""" + + self.makeapirequest.side_effect = [ + {"value": []}, + {"value": [{"id": 0, "displayName": "test"}]}, + self.scheduled_actions, + ] + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + self.append_id, + False, + None, + ) + self.assertEqual(0, self.count["config_count"]) + + def test_backup_with_prefix(self): + """The count should be 0 if no data is returned.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "test", + self.append_id, + False, + None, + ) + self.assertEqual(1, self.count["config_count"]) + self.assertTrue( + os.path.exists( + f"{self.directory.path}/Compliance Policies/Policies/test_linuxMdm.json" + ) + ) + + def test_backup_with_prefix_no_match(self): + """The count should be 0 if no data is returned.""" + + self.compliance_policy["value"][0]["name"] = "linuxCompliancePolicy" + self.makeapirequest.side_effect = [ + self.compliance_policy, + {"value": [{"id": 0, "displayName": "test"}]}, + self.scheduled_actions, + ] + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "test", + self.append_id, + False, + None, + ) + self.assertEqual(0, self.count["config_count"]) + + def test_backup_append_id(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, "json", self.exclude, self.token, "", True, False, None + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Compliance Policies/Policies/test_linuxMdm__0.json" + ).exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Compliance Policies/Policies/test_linuxMdm__0.json" + ).exists() + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/Backup/Intune/test_backup_complianceScript.py b/tests/Backup/Intune/test_backup_complianceScript.py new file mode 100644 index 00000000..e7306cb3 --- /dev/null +++ b/tests/Backup/Intune/test_backup_complianceScript.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +"""This module tests backing up compliance.""" + +import json +import os.path +import unittest +from pathlib import Path +from unittest.mock import patch + +import yaml +from testfixtures import TempDirectory + +from src.IntuneCD.backup.Intune.backup_complianceScripts import savebackup + + +class TestBackupCompliance(unittest.TestCase): + """Test class for backup_compliance.""" + + def setUp(self): + self.directory = TempDirectory() + self.directory.create() + self.token = "token" + self.exclude = [] + self.append_id = False + self.saved_path = ( + f"{self.directory.path}/Compliance Policies/Scripts/TestScript." + ) + self.expected_data = { + "publisher": "intunecd", + "displayName": "TestScript", + "description": "", + "detectionScriptContent": "WW91IGZvdW5kIGEgc2VjcmV0IG1lc3NhZ2UsIGhvb3JheSE=", + "runAsAccount": "system", + "enforceSignatureCheck": False, + "runAs32Bit": False, + "roleScopeTagIds": ["Default"], + } + self.compliance_policy_script = { + "value": [ + { + "id": "0", + "publisher": "intunecd", + "displayName": "TestScript", + "description": "", + "detectionScriptContent": "WW91IGZvdW5kIGEgc2VjcmV0IG1lc3NhZ2UsIGhvb3JheSE=", + "runAsAccount": "system", + "enforceSignatureCheck": False, + "runAs32Bit": False, + "roleScopeTagIds": ["Default"], + } + ] + } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } + + self.makeapirequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_complianceScripts.makeapirequest" + ) + self.makeapirequest = self.makeapirequest_patch.start() + self.makeapirequest.return_value = self.compliance_policy_script + + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_complianceScripts.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + + self.batch_request_patch = patch( + "src.IntuneCD.backup.Intune.backup_complianceScripts.batch_request" + ) + self.batch_request = self.batch_request_patch.start() + self.batch_request.return_value = [self.compliance_policy_script["value"][0]] + + def tearDown(self): + self.directory.cleanup() + self.makeapirequest.stop() + self.makeAuditRequest.stop() + self.batch_request.stop() + + def test_backup_yml(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + output = "yaml" + count = savebackup( + self.directory.path, + output, + self.token, + "", + self.append_id, + False, + None, + ) + + with open(self.saved_path + output, "r", encoding="utf-8") as f: + data = json.dumps(yaml.safe_load(f)) + saved_data = json.loads(data) + + self.assertTrue( + Path(f"{self.directory.path}/Compliance Policies/Scripts").exists() + ) + self.assertEqual(self.expected_data, saved_data) + self.assertEqual(1, count["config_count"]) + + def test_backup_json(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + output = "json" + count = savebackup( + self.directory.path, + output, + self.token, + "", + self.append_id, + False, + None, + ) + + with open(self.saved_path + output, "r", encoding="utf-8") as f: + saved_data = json.load(f) + + self.assertTrue( + Path(f"{self.directory.path}/Compliance Policies/Scripts").exists() + ) + self.assertEqual(self.expected_data, saved_data) + self.assertEqual(1, count["config_count"]) + + def test_backup_with_no_returned_data(self): + """The count should be 0 if no data is returned.""" + + self.makeapirequest.return_value = {"value": []} + self.count = savebackup( + self.directory.path, + "json", + self.token, + "", + self.append_id, + False, + None, + ) + self.assertEqual(0, self.count["config_count"]) + + def test_backup_with_prefix(self): + """The count should be 0 if no data is returned.""" + + self.count = savebackup( + self.directory.path, + "json", + self.token, + "test", + self.append_id, + False, + None, + ) + self.assertEqual(1, self.count["config_count"]) + self.assertTrue( + os.path.exists( + f"{self.directory.path}/Compliance Policies/Scripts/TestScript.json" + ) + ) + + def test_backup_with_prefix_no_match(self): + """The count should be 0 if no data is returned.""" + + self.compliance_policy_script["value"][0]["displayName"] = "notTestScript" + self.makeapirequest.return_value = self.compliance_policy_script + self.count = savebackup( + self.directory.path, + "json", + self.token, + "test", + self.append_id, + False, + None, + ) + self.assertEqual(0, self.count["config_count"]) + + def test_backup_append_id(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, "json", self.token, "", True, False, None + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Compliance Policies/Scripts/TestScript__0.json" + ).exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Compliance Policies/Scripts/TestScript__0.json" + ).exists() + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/Backup/Intune/test_backup_reusablePolicySettings.py b/tests/Backup/Intune/test_backup_reusablePolicySettings.py new file mode 100644 index 00000000..95fd4659 --- /dev/null +++ b/tests/Backup/Intune/test_backup_reusablePolicySettings.py @@ -0,0 +1,249 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +"""This module tests backing up Reusable Policy Settings.""" + +import json +import os.path +import unittest +from pathlib import Path +from unittest.mock import patch + +import yaml +from testfixtures import TempDirectory + +from src.IntuneCD.backup.Intune.backup_reusablePolicySettings import savebackup + + +class TestBackupReusablePolicySettings(unittest.TestCase): + """Test class for backup_reusablePolicySettings.""" + + def setUp(self): + self.directory = TempDirectory() + self.directory.create() + self.token = "token" + self.exclude = [] + self.append_id = False + self.saved_path = f"{self.directory.path}/Compliance Policies/Scripts/testsh." + self.expected_data = { + "displayName": "testsh", + "description": "", + "settingDefinitionId": "linux_customcompliance_discoveryscript_reusablesetting", + "settingInstance": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance", + "settingDefinitionId": "linux_customcompliance_discoveryscript_reusablesetting", + "settingInstanceTemplateReference": None, + "simpleSettingValue": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationStringSettingValue", + "settingValueTemplateReference": None, + "value": "WW91IGZvdW5kIGEgc2VjcmV0IG1lc3NhZ2UsIGhvb3JheSE=", + }, + }, + } + self.reusable_policy_settings_policy_script = { + "value": [ + { + "id": "0", + "displayName": "testsh", + "description": "", + "settingDefinitionId": "linux_customcompliance_discoveryscript_reusablesetting", + "settingInstance": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance", + "settingDefinitionId": "linux_customcompliance_discoveryscript_reusablesetting", + "settingInstanceTemplateReference": None, + "simpleSettingValue": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationStringSettingValue", + "settingValueTemplateReference": None, + "value": "WW91IGZvdW5kIGEgc2VjcmV0IG1lc3NhZ2UsIGhvb3JheSE=", + }, + }, + } + ] + } + self.audit_data = { + "value": [ + { + "resources": [ + {"resourceId": "0", "auditResourceType": "MagicResource"} + ], + "activityDateTime": "2021-01-01T00:00:00Z", + "activityOperationType": "Patch", + "activityResult": "Success", + "actor": [{"auditActorType": "ItPro"}], + } + ] + } + + self.makeapirequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_reusablePolicySettings.makeapirequest" + ) + self.makeapirequest = self.makeapirequest_patch.start() + self.makeapirequest.side_effect = [ + self.reusable_policy_settings_policy_script, + self.reusable_policy_settings_policy_script["value"][0], + ] + + self.makeAuditRequest_patch = patch( + "src.IntuneCD.backup.Intune.backup_reusablePolicySettings.makeAuditRequest" + ) + self.makeAuditRequest = self.makeAuditRequest_patch.start() + self.makeAuditRequest.return_value = self.audit_data + + def tearDown(self): + self.directory.cleanup() + self.makeapirequest.stop() + self.makeAuditRequest.stop() + + def test_backup_yml(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + output = "yaml" + count = savebackup( + self.directory.path, + output, + self.token, + "", + self.append_id, + False, + None, + ) + + with open(self.saved_path + output, "r", encoding="utf-8") as f: + data = json.dumps(yaml.safe_load(f)) + saved_data = json.loads(data) + + self.assertTrue( + Path(f"{self.directory.path}/Compliance Policies/Scripts").exists() + ) + self.assertEqual(self.expected_data, saved_data) + self.assertEqual(1, count["config_count"]) + + def test_backup_json(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + output = "json" + count = savebackup( + self.directory.path, + output, + self.token, + "", + self.append_id, + False, + None, + ) + + with open(self.saved_path + output, "r", encoding="utf-8") as f: + saved_data = json.load(f) + + self.assertTrue( + Path(f"{self.directory.path}/Compliance Policies/Scripts").exists() + ) + self.assertEqual(self.expected_data, saved_data) + self.assertEqual(1, count["config_count"]) + + def test_backup_with_no_returned_data(self): + """The count should be 0 if no data is returned.""" + + self.makeapirequest.side_effect = [{"value": []}] + self.count = savebackup( + self.directory.path, + "json", + self.token, + "", + self.append_id, + False, + None, + ) + self.assertEqual(0, self.count["config_count"]) + + def test_backup_with_prefix(self): + """The count should be 0 if no data is returned.""" + + self.count = savebackup( + self.directory.path, + "json", + self.token, + "test", + self.append_id, + False, + None, + ) + self.assertEqual(1, self.count["config_count"]) + self.assertTrue( + os.path.exists( + f"{self.directory.path}/Compliance Policies/Scripts/testsh.json" + ) + ) + + def test_backup_with_prefix_no_match(self): + """The count should be 0 if no data is returned.""" + + self.reusable_policy_settings_policy_script["value"][0][ + "displayName" + ] = "notTestScript" + self.makeapirequest.side_effect = [ + self.reusable_policy_settings_policy_script, + self.reusable_policy_settings_policy_script["value"][0], + ] + self.count = savebackup( + self.directory.path, + "json", + self.token, + "test", + self.append_id, + False, + None, + ) + self.assertEqual(0, self.count["config_count"]) + + def test_backup_append_id(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, "json", self.token, "", True, False, None + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Compliance Policies/Scripts/testsh__0.json" + ).exists() + ) + + def test_backup_scope_tags_and_audit(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.count = savebackup( + self.directory.path, + "json", + self.token, + "", + True, + True, + [{"id": 0, "displayName": "default"}], + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Compliance Policies/Scripts/testsh__0.json" + ).exists() + ) + + def test_backup_no_settingDefinitionId(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + + self.reusable_policy_settings_policy_script["value"][0].pop( + "settingDefinitionId" + ) + self.makeapirequest.side_effect = [ + self.reusable_policy_settings_policy_script, + self.reusable_policy_settings_policy_script["value"][0], + ] + self.count = savebackup( + self.directory.path, "json", self.token, "", True, False, None + ) + + self.assertEqual(0, self.count["config_count"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/Update/Intune/test_update_compliance.py b/tests/Update/Intune/test_update_compliance.py index 0115b1da..ecc4d957 100644 --- a/tests/Update/Intune/test_update_compliance.py +++ b/tests/Update/Intune/test_update_compliance.py @@ -204,6 +204,57 @@ def test_update_scope_tags(self): self.assertEqual(self.makeapirequestPatch.call_count, 1) self.assertEqual(self.post_assignment_update.call_count, 1) + def test_update_complianceScriptPolicy(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["deviceComplianceScriptName"] = "test" + self.repo_data["deviceCompliancePolicyScript"] = { + "deviceComplianceScriptId": "1" + } + self.makeapirequest.side_effect = [ + self.mem_data, + { + "value": [{"id": "0", "displayName": "test"}], + }, + ] + + self.count = update( + self.directory.path, self.token, assignment=True, remove=False + ) + + self.assertEqual(self.count[0].count, 2) + + def test_update_complianceScriptPolicy_platform(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["platforms"] = "linux" + self.count = update( + self.directory.path, self.token, assignment=True, remove=False + ) + + self.assertEqual(self.count, []) + + def test_update_complianceScriptPolicy_not_found(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["deviceComplianceScriptName"] = "test" + self.repo_data["displayName"] = "test1" + self.repo_data["deviceCompliancePolicyScript"] = { + "deviceComplianceScriptId": "1" + } + self.makeapirequest.side_effect = [ + self.mem_data, + { + "value": [{"id": "0", "displayName": "test"}], + }, + ] + + self.count = update( + self.directory.path, self.token, assignment=True, remove=False + ) + + self.assertEqual(self.makeapirequestPost.call_count, 1) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_compliancePolicies.py b/tests/Update/Intune/test_update_compliancePolicies.py new file mode 100644 index 00000000..cae3d525 --- /dev/null +++ b/tests/Update/Intune/test_update_compliancePolicies.py @@ -0,0 +1,397 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +"""This module tests updating Compliance Policies.""" + +import unittest +from unittest.mock import patch + +from testfixtures import TempDirectory + +from src.IntuneCD.update.Intune.update_compliancePolicies import update + + +class TestUpdateCompliancePolicies(unittest.TestCase): + """Test class for update_compliancePolicies.""" + + def setUp(self): + self.directory = TempDirectory() + self.directory.create() + self.directory.makedir("Compliance Policies") + self.directory.write( + "Compliance Policies/Policies/test.json", + '{"test": "test"}', + encoding="utf-8", + ) + self.directory.write( + "Compliance Policies/Policies/test.txt", "txt", encoding="utf-8" + ) + self.token = "token" + self.mem_data = { + "value": [ + { + "creationSource": None, + "id": "0", + "description": "", + "name": "test", + "platforms": "linux", + "roleScopeTagIds": ["Default"], + "settingCount": 1, + "technologies": "linuxMdm", + "settings@odata.context": "https://graph.microsoft.com/beta/$metadata#deviceManagement/compliancePolicies('15db4b21-d2a4-41f2-aa53-7267f6ba6a7e')/settings", + "settings": [ + { + "id": "0", + "settingInstance": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance", + "settingDefinitionId": "linux_passwordpolicy_minimumdigits", + "settingInstanceTemplateReference": None, + "simpleSettingValue": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationIntegerSettingValue", + "settingValueTemplateReference": None, + "value": 1, + }, + }, + } + ], + } + ] + } + self.repo_data = { + "creationSource": None, + "description": "", + "name": "test", + "platforms": "linux", + "roleScopeTagIds": ["Default"], + "settingCount": 1, + "technologies": "linuxMdm", + "settings@odata.context": "https://graph.microsoft.com/beta/$metadata#deviceManagement/compliancePolicies('15db4b21-d2a4-41f2-aa53-7267f6ba6a7e')/settings", + "settings": [ + { + "id": "0", + "settingInstance": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance", + "settingDefinitionId": "linux_passwordpolicy_minimumdigits", + "settingInstanceTemplateReference": None, + "simpleSettingValue": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationIntegerSettingValue", + "settingValueTemplateReference": None, + "value": 2, + }, + }, + } + ], + "scheduledActionsForRule": [ + { + "ruleName": None, + "scheduledActionConfigurations": [ + { + "gracePeriodHours": 0, + "actionType": "block", + "notificationTemplateId": "00000000-0000-0000-0000-000000000000", + "notificationMessageCCList": [], + } + ], + } + ], + "assignments": [ + { + "source": "direct", + "target": { + "@odata.type": "#microsoft.graph.groupAssignmentTarget", + "deviceAndAppManagementAssignmentFilterId": None, + "deviceAndAppManagementAssignmentFilterType": "none", + "groupName": "Department 2", + "groupType": "StaticMembership", + }, + } + ], + } + self.script_settings = { + "id": "0", + "roleScopeTagIds": ["Default"], + "settingInstance": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance", + "settingDefinitionId": "linux_customcompliance_required", + "settingInstanceTemplateReference": None, + "choiceSettingValue": { + "settingValueTemplateReference": None, + "value": "linux_customcompliance_required_true", + "children": [ + { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance", + "settingDefinitionId": "linux_customcompliance_discoveryscript", + "settingInstanceTemplateReference": None, + "simpleSettingValue": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationReferenceSettingValue", + "settingValueTemplateReference": None, + "value": "33d9b35d-0bc5-4ba1-ada4-139d97b2f756", + "note": None, + }, + }, + { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance", + "settingDefinitionId": "linux_customcompliance_rules", + "settingInstanceTemplateReference": None, + "simpleSettingValue": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationStringSettingValue", + "settingValueTemplateReference": None, + "value": "ewogICAgIlJ1bGVzIjpbIAogICAgICAgIHsgCiAgICAgICAgICAgIlNldHRpbmdOYW1lIjoidGVzdCIsCiAgICAgICAgIHsKXQogICAgfQ==", + }, + }, + ], + }, + }, + } + + self.batch_assignment_patch = patch( + "src.IntuneCD.update.Intune.update_compliancePolicies.batch_assignment" + ) + self.batch_assignment = self.batch_assignment_patch.start() + + self.object_assignment_patch = patch( + "src.IntuneCD.update.Intune.update_compliancePolicies.get_object_assignment" + ) + self.object_assignment = self.object_assignment_patch.start() + + self.makeapirequest_patch = patch( + "src.IntuneCD.update.Intune.update_compliancePolicies.makeapirequest" + ) + self.makeapirequest = self.makeapirequest_patch.start() + self.makeapirequest.return_value = self.mem_data + + self.update_assignment_patch = patch( + "src.IntuneCD.update.Intune.update_compliancePolicies.update_assignment" + ) + self.update_assignment = self.update_assignment_patch.start() + + self.load_file_patch = patch( + "src.IntuneCD.update.Intune.update_compliancePolicies.load_file" + ) + self.load_file = self.load_file_patch.start() + self.load_file.return_value = self.repo_data + + self.post_assignment_update_patch = patch( + "src.IntuneCD.update.Intune.update_compliancePolicies.post_assignment_update" + ) + self.post_assignment_update = self.post_assignment_update_patch.start() + + self.makeapirequestPatch_patch = patch( + "src.IntuneCD.update.Intune.update_compliancePolicies.makeapirequestPatch" + ) + self.makeapirequestPatch = self.makeapirequestPatch_patch.start() + + self.makeapirequestPost_patch = patch( + "src.IntuneCD.update.Intune.update_compliancePolicies.makeapirequestPost" + ) + self.makeapirequestPost = self.makeapirequestPost_patch.start() + self.makeapirequestPost.return_value = {"id": "0"} + + self.makeapirequestDelete_patch = patch( + "src.IntuneCD.update.Intune.update_compliancePolicies.makeapirequestDelete" + ) + self.makeapirequestDelete = self.makeapirequestDelete_patch.start() + + self.makeapirequestPut_patch = patch( + "src.IntuneCD.update.Intune.update_compliancePolicies.makeapirequestPut" + ) + self.makeapirequestPut = self.makeapirequestPut_patch.start() + + def tearDown(self): + self.directory.cleanup() + self.batch_assignment.stop() + self.object_assignment.stop() + self.makeapirequest.stop() + self.update_assignment.stop() + self.load_file.stop() + self.post_assignment_update.stop() + self.makeapirequestPatch.stop() + self.makeapirequestPost.stop() + self.makeapirequestDelete.stop() + self.makeapirequestPut.stop() + + def test_update_with_diffs_and_assignment(self): + """The count should be 2 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["scheduledActionsForRule"][0]["scheduledActionConfigurations"][ + 0 + ]["gracePeriodHours"] = 0 + self.repo_data["description"] = "test1" + + self.makeapirequest.side_effect = [ + self.mem_data, + { + "value": [ + { + "id": "1", + "scheduledActionConfigurations": [ + { + "id": "cffdcc1f-400f-400b-a7f9-3a2fb63412f8", + "gracePeriodHours": 1, + "actionType": "block", + "notificationTemplateId": "00000000-0000-0000-0000-000000000000", + "notificationMessageCCList": [], + } + ], + } + ] + }, + ] + + self.count = update( + self.directory.path, self.token, assignment=True, remove=False, report=False + ) + + self.assertEqual(self.count[0].count, 3) + self.assertEqual(self.makeapirequestPut.call_count, 1) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 1) + + def test_update_with_diffs_no_assignment(self): + """The count should be 2 and the makeapirequestPatch should be called.""" + + self.count = update( + self.directory.path, self.token, assignment=False, remove=True + ) + + self.assertEqual(self.count[0].count, 1) + self.assertEqual(self.makeapirequestPut.call_count, 1) + self.assertEqual(self.post_assignment_update.call_count, 0) + + def test_update_with_no_diffs_and_assignment(self): + """The count should be 0, the post_assignment_update should be called, + and makeapirequestPatch should not be called.""" + + self.mem_data["value"][0]["settings"][0]["settingInstance"][ + "simpleSettingValue" + ]["value"] = 2 + + self.count = update( + self.directory.path, self.token, assignment=True, remove=True + ) + + self.assertEqual(self.count[0].count, 0) + self.assertEqual(self.makeapirequestPut.call_count, 0) + self.assertEqual(self.post_assignment_update.call_count, 1) + + def test_update_with_no_diffs_no_assignment(self): + """The count should be 0, the post_assignment_update and makeapirequestPatch should not be called.""" + + self.mem_data["value"][0]["settings"][0]["settingInstance"][ + "simpleSettingValue" + ]["value"] = 2 + + self.count = update( + self.directory.path, self.token, assignment=False, remove=True + ) + + self.assertEqual(self.count[0].count, 0) + self.assertEqual(self.makeapirequestPut.call_count, 0) + self.assertEqual(self.post_assignment_update.call_count, 0) + + def test_update_config_not_found_and_assignment(self): + """The count should be 0, the post_assignment_update and makeapirequestPost should be called.""" + + self.repo_data["name"] = "test1" + + self.count = update( + self.directory.path, self.token, assignment=True, remove=False + ) + + self.assertEqual(self.count, []) + self.assertEqual(self.makeapirequestPost.call_count, 2) + self.assertEqual(self.post_assignment_update.call_count, 1) + + def test_remove_config(self): + """makeapirequestDelete should be called.""" + + self.mem_data["value"][0]["name"] = "test1" + + self.update = update(self.directory.path, self.token, report=False, remove=True) + + self.assertEqual(self.makeapirequestDelete.call_count, 1) + + def test_update_with_detection_script(self): + """The count should be 0, the post_assignment_update and makeapirequestPatch should not be called.""" + + self.repo_data["detectionScriptName"] = "test1" + self.repo_data["description"] = "test1" + self.repo_data["settings"] = [self.script_settings] + self.mem_data["value"][0]["settings"][0]["settingInstance"][ + "simpleSettingValue" + ]["value"] = 2 + + self.makeapirequest.side_effect = [ + self.mem_data, + { + "value": [ + { + "id": "1", + "scheduledActionConfigurations": [ + { + "id": "cffdcc1f-400f-400b-a7f9-3a2fb63412f8", + "gracePeriodHours": 1, + "actionType": "block", + "notificationTemplateId": "00000000-0000-0000-0000-000000000000", + "notificationMessageCCList": [], + } + ], + } + ] + }, + {"value": [{"displayName": "test1", "id": "0"}]}, + ] + + self.count = update( + self.directory.path, self.token, assignment=False, remove=True + ) + + self.assertEqual(self.count[0].count, 2) + self.assertEqual(self.makeapirequestPut.call_count, 0) + self.assertEqual(self.post_assignment_update.call_count, 0) + + def test_update_with_detection_script_not_found(self): + """The count should be 0, the post_assignment_update and makeapirequestPatch should not be called.""" + + self.repo_data["name"] = "test1" + self.repo_data["detectionScriptName"] = "test1" + self.repo_data["settings"] = [self.script_settings] + self.makeapirequest.return_value = {"value": []} + + self.count = update( + self.directory.path, self.token, assignment=False, remove=True + ) + + self.assertEqual(self.makeapirequestPost.call_count, 2) + self.assertEqual(self.post_assignment_update.call_count, 1) + + def test_update_no_technology(self): + """The count should be 0, the post_assignment_update and makeapirequestPatch should not be called.""" + + self.repo_data.pop("technologies") + + self.count = update( + self.directory.path, self.token, assignment=False, remove=True + ) + + self.assertEqual(self.count, []) + + def test_update_with_scope_tags(self): + """The count should be 0, the post_assignment_update and makeapirequestPatch should not be called.""" + self.mem_data["value"][0]["settings"][0]["settingInstance"][ + "simpleSettingValue" + ]["value"] = 2 + + self.count = update( + self.directory.path, + self.token, + assignment=False, + remove=True, + scope_tags=[{"id": "0", "displayName": "test"}], + ) + + self.assertEqual(self.count[0].count, 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/Update/Intune/test_update_complianceScripts.py b/tests/Update/Intune/test_update_complianceScripts.py new file mode 100644 index 00000000..bfc7091d --- /dev/null +++ b/tests/Update/Intune/test_update_complianceScripts.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +"""This module tests updating Compliance Scripts.""" + +import unittest +from unittest.mock import patch + +from testfixtures import TempDirectory + +from src.IntuneCD.update.Intune.update_complianceScripts import update + + +@patch("time.sleep", return_value=None) +class TestUpdateComplianceScripts(unittest.TestCase): + """Test class for update_complianceScripts.""" + + def setUp(self): + self.directory = TempDirectory() + self.directory.create() + self.directory.makedir("Compliance Policies/Scripts") + self.directory.makedir("Compliance Policies/Scripts/Script Data") + self.directory.write( + "Compliance Policies/Scripts/test.json", + '{"test": "test"}', + encoding="utf-8", + ) + self.directory.write( + "Compliance Policies/Scripts/Script Data/test.sh", + "You found a secret message, hooray!", + encoding="utf-8", + ) + self.token = "token" + self.mem_script_content = "WW91IGZvdW5kIGEgc2VjcmV0IG1lc3NhZ2Us" + self.repo_script_content = "WW91IGZvdW5kIGEgc2VjcmV0IG1lc3NhZ2UsIGhvb3JheSE=" + self.mem_detectionScript_data = { + "value": [ + { + "@odata.type": "test", + "id": "0", + "displayName": "test", + "testvalue": "test", + "detectionScriptContent": self.mem_script_content, + } + ] + } + self.mem_data = { + "@odata.type": "test", + "id": "0", + "displayName": "test", + "testvalue": "test", + "detectionScriptContent": self.mem_script_content, + } + self.repo_data = { + "@odata.type": "test", + "id": "0", + "displayName": "test", + "testvalue": "test", + "detectionScriptContent": self.repo_script_content, + } + + self.makeapirequest_patch = patch( + "src.IntuneCD.update.Intune.update_complianceScripts.makeapirequest" + ) + self.makeapirequest = self.makeapirequest_patch.start() + self.makeapirequest.return_value = self.mem_data + + self.load_file_patch = patch( + "src.IntuneCD.update.Intune.update_complianceScripts.load_file" + ) + self.load_file = self.load_file_patch.start() + self.load_file.return_value = self.repo_data + + self.makeapirequestPatch_patch = patch( + "src.IntuneCD.update.Intune.update_complianceScripts.makeapirequestPatch" + ) + self.makeapirequestPatch = self.makeapirequestPatch_patch.start() + + self.makeapirequestPost_patch = patch( + "src.IntuneCD.update.Intune.update_complianceScripts.makeapirequestPost" + ) + self.makeapirequestPost = self.makeapirequestPost_patch.start() + self.makeapirequestPost.return_value = {"id": "0"} + + self.makeapirequestDelete_patch = patch( + "src.IntuneCD.update.Intune.update_complianceScripts.makeapirequestDelete" + ) + self.makeapirequestDelete = self.makeapirequestDelete_patch.start() + + def tearDown(self): + self.directory.cleanup() + self.makeapirequest.stop() + self.load_file.stop() + self.makeapirequestPatch.stop() + self.makeapirequestPost.stop() + self.makeapirequestDelete.stop() + + def test_update_with_diffs(self, _): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["testvalue"] = "test1" + self.makeapirequest.side_effect = [self.mem_detectionScript_data, self.mem_data] + + self.count = update( + self.directory.path, self.token, report=False, remove=False, scope_tags="" + ) + + self.assertEqual(self.count[0].count, 2) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + + def test_update_with_no_diffs(self, _): + """The count should be 0, the post_assignment_update should be called, + and makeapirequestPatch should not be called.""" + + self.mem_data["testvalue"] = "test" + self.mem_data["detectionScriptContent"] = self.repo_script_content + + self.makeapirequest.side_effect = [self.mem_detectionScript_data, self.mem_data] + + self.count = update( + self.directory.path, self.token, report=False, remove=False, scope_tags="" + ) + + self.assertEqual(self.count[0].count, 0) + self.assertEqual(self.makeapirequestPatch.call_count, 0) + + def test_update_config_not_found(self, _): + """The count should be 0, the post_assignment_update and makeapirequestPost should be called.""" + + self.mem_detectionScript_data["value"][0]["displayName"] = "test1" + self.makeapirequest.return_value = self.mem_detectionScript_data + + self.count = update( + self.directory.path, self.token, report=False, remove=False, scope_tags="" + ) + + self.assertEqual(self.count, []) + self.assertEqual(self.makeapirequestPost.call_count, 1) + + def test_remove_config(self, _): + """makeapirequestDelete should be called.""" + + self.mem_detectionScript_data["value"].append( + {"displayName": "test2", "id": "2"} + ) + self.makeapirequest.side_effect = [self.mem_detectionScript_data, self.mem_data] + + self.update = update( + self.directory.path, self.token, report=False, remove=True, scope_tags="" + ) + + self.assertEqual(self.makeapirequestDelete.call_count, 1) + + def test_update_scope_tags(self, _): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["testvalue"] = "test1" + self.makeapirequest.side_effect = [self.mem_detectionScript_data, self.mem_data] + + self.count = update( + self.directory.path, + self.token, + remove=False, + scope_tags=["test"], + ) + + self.assertEqual(self.count[0].count, 2) + self.assertEqual(self.makeapirequestPatch.call_count, 1) + + def test_update_settingDefinitionId(self, _): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["settingDefinitionId"] = "test" + self.makeapirequest.side_effect = [self.mem_detectionScript_data, self.mem_data] + + self.count = update( + self.directory.path, self.token, report=False, remove=False, scope_tags="" + ) + + self.assertEqual(self.count, []) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/Update/Intune/test_update_reusablePolicySettings.py b/tests/Update/Intune/test_update_reusablePolicySettings.py new file mode 100644 index 00000000..a8ccbbca --- /dev/null +++ b/tests/Update/Intune/test_update_reusablePolicySettings.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +"""This module tests updating Reusable Policy Settings.""" + +import unittest +from unittest.mock import patch + +from testfixtures import TempDirectory + +from src.IntuneCD.update.Intune.update_reusablePolicySettings import update + + +@patch("time.sleep", return_value=None) +class TestUpdateReusablePolicySettings(unittest.TestCase): + """Test class for update_reusablePolicySettings.""" + + def setUp(self): + self.directory = TempDirectory() + self.directory.create() + self.directory.makedir("Compliance Policies/Scripts") + self.directory.makedir("Compliance Policies/Scripts/Script Data") + self.directory.write( + "Compliance Policies/Scripts/test.json", + '{"test": "test"}', + encoding="utf-8", + ) + self.directory.write( + "Compliance Policies/Scripts/Script Data/test.sh", + "You found a secret message, hooray!", + encoding="utf-8", + ) + self.token = "token" + self.mem_script_content = "WW91IGZvdW5kIGEgc2VjcmV0IG1lc3NhZ2Us" + self.repo_script_content = "WW91IGZvdW5kIGEgc2VjcmV0IG1lc3NhZ2UsIGhvb3JheSE=" + self.mem_detectionScript_data = { + "value": [ + { + "@odata.type": "test", + "id": "0", + "displayName": "test", + "testvalue": "test", + "detectionScriptContent": self.mem_script_content, + } + ] + } + self.mem_data = { + "value": [ + { + "displayName": "test", + "description": "", + "id": "0", + "settingDefinitionId": "linux_customcompliance_discoveryscript_reusablesetting", + "settingInstance": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance", + "settingDefinitionId": "linux_customcompliance_discoveryscript_reusablesetting", + "settingInstanceTemplateReference": None, + "simpleSettingValue": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationStringSettingValue", + "settingValueTemplateReference": None, + "value": self.mem_script_content, + }, + }, + } + ] + } + self.repo_data = { + "displayName": "test", + "description": "", + "settingDefinitionId": "linux_customcompliance_discoveryscript_reusablesetting", + "settingInstance": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance", + "settingDefinitionId": "linux_customcompliance_discoveryscript_reusablesetting", + "settingInstanceTemplateReference": None, + "simpleSettingValue": { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationStringSettingValue", + "settingValueTemplateReference": None, + "value": self.repo_script_content, + }, + }, + } + + self.makeapirequest_patch = patch( + "src.IntuneCD.update.Intune.update_reusablePolicySettings.makeapirequest" + ) + self.makeapirequest = self.makeapirequest_patch.start() + self.makeapirequest.side_effect = [self.mem_data, self.mem_data["value"][0]] + + self.load_file_patch = patch( + "src.IntuneCD.update.Intune.update_reusablePolicySettings.load_file" + ) + self.load_file = self.load_file_patch.start() + self.load_file.return_value = self.repo_data + + self.makeapirequestPut_patch = patch( + "src.IntuneCD.update.Intune.update_reusablePolicySettings.makeapirequestPut" + ) + self.makeapirequestPut = self.makeapirequestPut_patch.start() + + self.makeapirequestPost_patch = patch( + "src.IntuneCD.update.Intune.update_reusablePolicySettings.makeapirequestPost" + ) + self.makeapirequestPost = self.makeapirequestPost_patch.start() + self.makeapirequestPost.return_value = {"id": "0"} + + self.makeapirequestDelete_patch = patch( + "src.IntuneCD.update.Intune.update_reusablePolicySettings.makeapirequestDelete" + ) + self.makeapirequestDelete = self.makeapirequestDelete_patch.start() + + def tearDown(self): + self.directory.cleanup() + self.makeapirequest.stop() + self.load_file.stop() + self.makeapirequestPut.stop() + self.makeapirequestPost.stop() + self.makeapirequestDelete.stop() + + def test_update_with_diffs(self, _): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["description"] = "test1" + self.makeapirequest.side_effect = [self.mem_data, self.mem_data["value"][0]] + + self.count = update(self.directory.path, self.token, report=False, remove=False) + + self.assertEqual(self.count[0].count, 2) + self.assertEqual(self.makeapirequestPut.call_count, 1) + + def test_update_with_no_diffs(self, _): + """The count should be 0, the post_assignment_update should be called, + and makeapirequestPatch should not be called.""" + + self.mem_data["value"][0]["settingInstance"]["simpleSettingValue"][ + "value" + ] = self.repo_script_content + + self.makeapirequest.side_effect = [self.mem_data, self.mem_data["value"][0]] + + self.count = update(self.directory.path, self.token, report=False, remove=False) + + self.assertEqual(self.count[0].count, 0) + self.assertEqual(self.makeapirequestPut.call_count, 0) + + def test_update_config_not_found(self, _): + """The count should be 0, the post_assignment_update and makeapirequestPost should be called.""" + + self.repo_data["displayName"] = "test2" + + self.count = update(self.directory.path, self.token, report=False, remove=False) + + self.assertEqual(self.count, []) + self.assertEqual(self.makeapirequestPost.call_count, 1) + + def test_remove_config(self, _): + """makeapirequestDelete should be called.""" + + self.mem_data["value"].append({"displayName": "test2", "id": "2"}) + self.makeapirequest.side_effect = [self.mem_data, self.mem_data["value"][0]] + + self.update = update(self.directory.path, self.token, report=False, remove=True) + + self.assertEqual(self.makeapirequestDelete.call_count, 1) + + def test_update_config_no_settingDefinitionId(self, _): + """The count should be 0, the post_assignment_update and makeapirequestPost should be called.""" + + self.repo_data.pop("settingDefinitionId") + + self.count = update(self.directory.path, self.token, report=False, remove=False) + + self.assertEqual(self.count, []) + + +if __name__ == "__main__": + unittest.main() From 3b74a58de81675a4f1e71e5db59b290295355d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Sun, 3 Mar 2024 12:26:20 +0100 Subject: [PATCH 29/35] bump to 2.2.0.beta7 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 268dc7c6..ac89925c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = IntuneCD -version = 2.2.0.beta6 +version = 2.2.0.beta7 author = Tobias Almén author_email = almenscorner@outlook.com description = Tool to backup and update configurations in Intune From aaaf81906f23d8d83160ff69237f6d9312640f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Mon, 4 Mar 2024 14:17:55 +0100 Subject: [PATCH 30/35] add script extension when using append id --- src/IntuneCD/backup/Intune/backup_complianceScripts.py | 2 +- src/IntuneCD/backup/Intune/backup_reusablePolicySettings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IntuneCD/backup/Intune/backup_complianceScripts.py b/src/IntuneCD/backup/Intune/backup_complianceScripts.py index c544effb..3522884c 100644 --- a/src/IntuneCD/backup/Intune/backup_complianceScripts.py +++ b/src/IntuneCD/backup/Intune/backup_complianceScripts.py @@ -65,7 +65,7 @@ def savebackup(path, output, token, prefix, append_id, audit, scope_tags): # Get filename without illegal characters fname = clean_filename(script_data["displayName"]) - script_file_name = script_data["displayName"] + script_file_name = f"{script_data['displayName']}.ps1" if append_id: fname = f"{fname}__{graph_id}" script_name = script_data["displayName"].replace(".ps1", "") diff --git a/src/IntuneCD/backup/Intune/backup_reusablePolicySettings.py b/src/IntuneCD/backup/Intune/backup_reusablePolicySettings.py index 7015e322..1bfa92bb 100644 --- a/src/IntuneCD/backup/Intune/backup_reusablePolicySettings.py +++ b/src/IntuneCD/backup/Intune/backup_reusablePolicySettings.py @@ -67,7 +67,7 @@ def savebackup(path, output, token, prefix, append_id, audit, scope_tags): # Get filename without illegal characters fname = clean_filename(policy["displayName"]) - script_file_name = script_data["displayName"] + script_file_name = f"{script_data['displayName']}.sh" if append_id: fname = f"{fname}__{graph_id}" script_name = policy["displayName"].replace(".sh", "") From a120abcac61face68c9cc0e26ea86adb73bced44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Mon, 4 Mar 2024 14:18:23 +0100 Subject: [PATCH 31/35] always add "script name" key --- src/IntuneCD/backup/Intune/backup_compliance.py | 11 +++++++++++ .../backup/Intune/backup_compliancePolicies.py | 2 ++ 2 files changed, 13 insertions(+) diff --git a/src/IntuneCD/backup/Intune/backup_compliance.py b/src/IntuneCD/backup/Intune/backup_compliance.py index 5673b8c8..20594113 100644 --- a/src/IntuneCD/backup/Intune/backup_compliance.py +++ b/src/IntuneCD/backup/Intune/backup_compliance.py @@ -68,6 +68,17 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tag "scheduledActionConfigurations" ]: remove_keys(scheduled_config) + if policy.get("deviceCompliancePolicyScript", None): + # Get the name of the script + script_name = makeapirequest( + "https://graph.microsoft.com/beta/deviceManagement/deviceComplianceScripts/" + + policy["deviceCompliancePolicyScript"]["deviceComplianceScriptId"], + token, + ) + if script_name: + policy["deviceComplianceScriptName"] = script_name["displayName"] + else: + policy["deviceComplianceScriptName"] = None # Get filename without illegal characters fname = clean_filename(policy["displayName"]) diff --git a/src/IntuneCD/backup/Intune/backup_compliancePolicies.py b/src/IntuneCD/backup/Intune/backup_compliancePolicies.py index 039a33d5..d845f897 100644 --- a/src/IntuneCD/backup/Intune/backup_compliancePolicies.py +++ b/src/IntuneCD/backup/Intune/backup_compliancePolicies.py @@ -104,6 +104,8 @@ def savebackup(path, output, exclude, token, prefix, append_id, audit, scope_tag policy["detectionScriptName"] = detection_script["value"][0][ "displayName" ] + else: + policy["detectionScriptName"] = None # get scheduledActionsForRule scheduledActionsForRule = makeapirequest( From a37444092204f1f545350d31bb8dfc10e03e6a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Mon, 4 Mar 2024 14:18:57 +0100 Subject: [PATCH 32/35] skip update and creation if script does not exist --- .../update/Intune/update_compliance.py | 20 +++++-- .../Intune/update_compliancePolicies.py | 22 +++++++- tests/Backup/Intune/test_backup_compliance.py | 51 ++++++++++++++++++ .../Intune/test_backup_compliancePolicies.py | 24 +++++++++ tests/Update/Intune/test_update_compliance.py | 54 ++++++++++++++++++- .../Intune/test_update_compliancePolicies.py | 24 ++++++++- 6 files changed, 187 insertions(+), 8 deletions(-) diff --git a/src/IntuneCD/update/Intune/update_compliance.py b/src/IntuneCD/update/Intune/update_compliance.py index ac0c0447..e3b389dd 100644 --- a/src/IntuneCD/update/Intune/update_compliance.py +++ b/src/IntuneCD/update/Intune/update_compliance.py @@ -39,7 +39,9 @@ def _set_compliance_script_id(data, token): "deviceComplianceScriptId" ] = compliance_script_id["value"][0]["id"] - return data + return data + + return False def update( @@ -125,8 +127,14 @@ def update( ): remove_keys(scheduled_config) - if repo_data.get("deviceComplianceScriptName"): + if "deviceComplianceScriptName" in repo_data: + script_name = repo_data["deviceComplianceScriptName"] repo_data = _set_compliance_script_id(repo_data, token) + if repo_data is False: + print( + f"Compliance script {script_name} not found, Compliance Policy not updated" + ) + continue diff = DeepDiff( data["value"], @@ -220,8 +228,14 @@ def update( + repo_data["displayName"] ) if report is False: - if repo_data.get("deviceComplianceScriptName"): + if "deviceComplianceScriptName" in repo_data: + script_name = repo_data["deviceComplianceScriptName"] repo_data = _set_compliance_script_id(repo_data, token) + if repo_data is False: + print( + f"Compliance script {script_name} not found, Compliance Policy not created" + ) + continue request_json = json.dumps(repo_data) post_request = makeapirequestPost( diff --git a/src/IntuneCD/update/Intune/update_compliancePolicies.py b/src/IntuneCD/update/Intune/update_compliancePolicies.py index 97c935bc..7e2c188e 100644 --- a/src/IntuneCD/update/Intune/update_compliancePolicies.py +++ b/src/IntuneCD/update/Intune/update_compliancePolicies.py @@ -96,7 +96,9 @@ def _set_detection_script_id(data, token): script_id_path = script_id_path + ["simpleSettingValue", "value"] data = _set_value_from_path(data, script_id["value"][0]["id"], script_id_path) - return data + return data + + return False def update( @@ -191,6 +193,15 @@ def update( ): remove_keys(scheduled_config) + if "detectionScriptName" in repo_data: + script_name = repo_data["detectionScriptName"] + repo_data = _set_detection_script_id(repo_data, token) + if repo_data is False: + print( + f"Detection script {script_name} not found, Compliance Policy not updated" + ) + continue + diff = DeepDiff( data["value"], repo_data, @@ -316,8 +327,15 @@ def update( "Compliance Policy not found, creating Policy: " + repo_data["name"] ) if report is False: - if repo_data.get("detectionScriptName"): + if "detectionScriptName" in repo_data: + script_name = repo_data["detectionScriptName"] repo_data = _set_detection_script_id(repo_data, token) + if repo_data is False: + print( + f"Detection script {script_name} not found, Compliance Policy not created" + ) + continue + repo_data = _remove_keys(repo_data) request_json = json.dumps(repo_data) post_request = makeapirequestPost( diff --git a/tests/Backup/Intune/test_backup_compliance.py b/tests/Backup/Intune/test_backup_compliance.py index 25b60654..34c5c6b1 100644 --- a/tests/Backup/Intune/test_backup_compliance.py +++ b/tests/Backup/Intune/test_backup_compliance.py @@ -240,6 +240,57 @@ def test_backup_scope_tags_and_audit(self): ).exists() ) + def test_backup_custom_compliance(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + self.compliance_policy["value"][0]["deviceCompliancePolicyScript"] = { + "deviceComplianceScriptId": "0" + } + self.makeapirequest.side_effect = [ + self.compliance_policy, + {"displayName": "test"}, + ] + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + "", + ) + + self.assertTrue( + Path( + f"{self.directory.path}/Compliance Policies/Policies/test_iosCompliancePolicy__0.json" + ).exists() + ) + self.assertEqual(self.makeapirequest.call_count, 2) + + def test_backup_custom_compliance_script_not_found(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + self.compliance_policy["value"][0]["deviceCompliancePolicyScript"] = { + "deviceComplianceScriptId": "0" + } + self.makeapirequest.side_effect = [self.compliance_policy, {}] + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + "", + ) + + self.assertEqual( + self.compliance_policy["value"][0]["deviceComplianceScriptName"], None + ) + self.assertEqual(self.makeapirequest.call_count, 2) + if __name__ == "__main__": unittest.main() diff --git a/tests/Backup/Intune/test_backup_compliancePolicies.py b/tests/Backup/Intune/test_backup_compliancePolicies.py index 49614978..2367d418 100644 --- a/tests/Backup/Intune/test_backup_compliancePolicies.py +++ b/tests/Backup/Intune/test_backup_compliancePolicies.py @@ -316,6 +316,30 @@ def test_backup_scope_tags_and_audit(self): ).exists() ) + def test_backup_custom_detection_script_not_found(self): + """The folder should be created, the file should have the expected contents, and the count should be 1.""" + self.makeapirequest.side_effect = [ + self.compliance_policy, + {"value": []}, + self.scheduled_actions, + ] + + self.count = savebackup( + self.directory.path, + "json", + self.exclude, + self.token, + "", + True, + True, + "", + ) + + self.assertEqual( + self.compliance_policy["value"][0]["detectionScriptName"], None + ) + self.assertEqual(self.makeapirequest.call_count, 3) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_compliance.py b/tests/Update/Intune/test_update_compliance.py index ecc4d957..42b4f8b2 100644 --- a/tests/Update/Intune/test_update_compliance.py +++ b/tests/Update/Intune/test_update_compliance.py @@ -237,7 +237,7 @@ def test_update_complianceScriptPolicy_platform(self): def test_update_complianceScriptPolicy_not_found(self): """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" - self.repo_data["deviceComplianceScriptName"] = "test" + self.repo_data["ComplianceScriptName"] = "test" self.repo_data["displayName"] = "test1" self.repo_data["deviceCompliancePolicyScript"] = { "deviceComplianceScriptId": "1" @@ -255,6 +255,58 @@ def test_update_complianceScriptPolicy_not_found(self): self.assertEqual(self.makeapirequestPost.call_count, 1) + def test_update_customCompliancePolicy(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["deviceComplianceScriptName"] = "test" + self.repo_data["deviceCompliancePolicyScript"] = { + "deviceComplianceScriptId": "1" + } + self.makeapirequest.side_effect = [ + self.mem_data, + {"value": [{"id": "0", "displayName": "test"}]}, + ] + self.count = update( + self.directory.path, self.token, assignment=True, remove=False + ) + + self.assertEqual(self.count[0].count, 2) + + def test_update_customCompliancePolicy_script_not_found(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["deviceComplianceScriptName"] = None + self.repo_data["deviceCompliancePolicyScript"] = { + "deviceComplianceScriptId": "1" + } + self.makeapirequest.side_effect = [ + self.mem_data, + {"value": []}, + ] + self.count = update( + self.directory.path, self.token, assignment=True, remove=False + ) + + self.assertEqual(self.count, []) + + def test_update_customCompliancePolicy_script_not_found_create(self): + """The count should be 1 and the post_assignment_update and makeapirequestPatch should be called.""" + + self.repo_data["displayName"] = "test1" + self.repo_data["deviceComplianceScriptName"] = "test" + self.repo_data["deviceCompliancePolicyScript"] = { + "deviceComplianceScriptId": "1" + } + self.makeapirequest.side_effect = [ + self.mem_data, + {"value": []}, + ] + self.count = update( + self.directory.path, self.token, assignment=True, remove=False, report=False + ) + + self.assertEqual(self.makeapirequestPost.call_count, 0) + if __name__ == "__main__": unittest.main() diff --git a/tests/Update/Intune/test_update_compliancePolicies.py b/tests/Update/Intune/test_update_compliancePolicies.py index cae3d525..1d09e8cb 100644 --- a/tests/Update/Intune/test_update_compliancePolicies.py +++ b/tests/Update/Intune/test_update_compliancePolicies.py @@ -323,6 +323,7 @@ def test_update_with_detection_script(self): self.makeapirequest.side_effect = [ self.mem_data, + {"value": [{"displayName": "test1", "id": "0"}]}, { "value": [ { @@ -362,8 +363,27 @@ def test_update_with_detection_script_not_found(self): self.directory.path, self.token, assignment=False, remove=True ) - self.assertEqual(self.makeapirequestPost.call_count, 2) - self.assertEqual(self.post_assignment_update.call_count, 1) + self.assertEqual(self.makeapirequestPost.call_count, 0) + self.assertEqual(self.post_assignment_update.call_count, 0) + + def test_update_with_detection_script_not_found_update(self): + """The count should be 0, the post_assignment_update and makeapirequestPatch should not be called.""" + + # self.repo_data["name"] = "test1" + self.repo_data["detectionScriptName"] = "test1" + self.repo_data["settings"] = [self.script_settings] + self.makeapirequest.side_effect = [ + self.mem_data, + {"value": [{"displayName": "test1", "id": "0"}]}, + {"value": []}, + ] + + self.count = update( + self.directory.path, self.token, assignment=False, remove=True + ) + + self.assertEqual(self.makeapirequestPost.call_count, 0) + self.assertEqual(self.post_assignment_update.call_count, 0) def test_update_no_technology(self): """The count should be 0, the post_assignment_update and makeapirequestPatch should not be called.""" From 618b9f4f4420a5cfb9ea42a00badcc7445a3b2cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Mon, 4 Mar 2024 14:23:26 +0100 Subject: [PATCH 33/35] fix typo --- src/IntuneCD/run_backup.py | 2 +- src/IntuneCD/run_update.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/IntuneCD/run_backup.py b/src/IntuneCD/run_backup.py index ed5401d4..e81668b2 100644 --- a/src/IntuneCD/run_backup.py +++ b/src/IntuneCD/run_backup.py @@ -126,7 +126,7 @@ def start(): "VPPusedLicenseCount", "GPlaySyncTime", "CompliancePartnerHeartbeat", - "DeviceCompliancePolicy", + "DeviceCompliancePolicies", "ComplianceScripts", "ReusablePolicySettings", "entraApplications", diff --git a/src/IntuneCD/run_update.py b/src/IntuneCD/run_update.py index f4477be4..f0096a7d 100644 --- a/src/IntuneCD/run_update.py +++ b/src/IntuneCD/run_update.py @@ -110,9 +110,10 @@ def start(): "DeviceCategories", "Roles", "ScopeTags", - "DeviceCompliancePolicy", + "DeviceCompliancePolicies", "ComplianceScripts", - "ReusablePolicySettings" "entraAuthenticationFlowsPolicy", + "ReusablePolicySettings", + "entraAuthenticationFlowsPolicy", "entraAuthenticationMethods", "entraAuthorizationPolicy", "entraB2BPolicy", From 59d9f5e9f4399b39b240927b3ae117f7f161d1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Mon, 4 Mar 2024 14:23:41 +0100 Subject: [PATCH 34/35] update module documentation --- src/IntuneCD/intunecdlib/process_audit_data.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/IntuneCD/intunecdlib/process_audit_data.py b/src/IntuneCD/intunecdlib/process_audit_data.py index 9c33a0c5..920e3d05 100644 --- a/src/IntuneCD/intunecdlib/process_audit_data.py +++ b/src/IntuneCD/intunecdlib/process_audit_data.py @@ -168,7 +168,7 @@ def _get_payload_from_audit_data(audit_data, compare_data): Gets the payload from the audit data. :param audit_data: The audit data to get the payload from. - :param pid: The resource ID to get the payload for. + :param compare_data: The data to compare the audit data to. """ records = [] @@ -189,8 +189,8 @@ def process_audit_data(audit_data, compare_data, path, file): Processes the audit data from Intune. :param audit_data: The audit data to process. - :param pid: The resource ID to process. - :param path: The path to the git repo. + :param compare_data: The data to compare the audit data to. + :param path: The path to the file. :param file: The file to process. """ From fce02095c0e5859fb41303e50222c6fccd8feac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Alm=C3=A9n?= <78877636+almenscorner@users.noreply.github.com> Date: Mon, 4 Mar 2024 14:26:45 +0100 Subject: [PATCH 35/35] bump to 2.2.0 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index ac89925c..12e88851 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = IntuneCD -version = 2.2.0.beta7 +version = 2.2.0 author = Tobias Almén author_email = almenscorner@outlook.com description = Tool to backup and update configurations in Intune