The last couple of weeks I’ve been focused on some API efforts for IT-Glue and was asked by a couple of partners if I couldn’t solve the problem that IT-Glue does not have a backup feature available. This makes it difficult to move away from the product, but also access you data in case of an emergency.
So to make sure that IT-Glue partners get some form of data portability and backups I’ve created the following script. The script connects to the IT-Glue API and creates a HTML and CSV export of all Flexible Assets and Passwords in IT-Glue.
It does not currently backup documents, as those are not exposed by the API. It also does not download attachments included on Flexible Assets. The export always creates 2 files; one HTML file for quick viewing, and a CSV file with all the information included.
I’ve also decided not to directly download all configurations as we store no data in there. If anyone wants to also download the configurations, let me know and I’ll edit the script a little.
Warning: The HTML files contain all your documentation, in plain-text format. Store this in a safe location or adapt the script to upload the data to your Azure Key Vault or secondary password management tool instead. Do not store these in a public location.
All you have to do is change the variables for your environment, APIKey, APIEndpoint, and the Export Directory.
The Unofficial IT-Glue Backup Script.
##################################################################### #The unofficial Kelvin Tegelaar IT-Glue Backup script. Run this script whenever you want to create a backup of the ITGlue database. #Creates a file called "password.html" with all passwords in Plain-text. please only store in secure location. #Creates folders per organisation, and copies flexible assets there as HTML table & CSV file for data portability. $APIKEy = "APIKEYHERE" $APIEndpoint = "https://api.eu.itglue.com" $ExportDir = "C:\Hello\ITGBackup" ##################################################################### Write-Host "Creating backup directory" -ForegroundColor Green if (!(Test-Path $ExportDir)) { new-item $ExportDir -ItemType Directory } #Header for HTML files, to make it look pretty. $head = @" <script> function myFunction() { const filter = document.querySelector('#myInput').value.toUpperCase(); const trs = document.querySelectorAll('table tr:not(.header)'); trs.forEach(tr => tr.style.display = [...tr.children].find(td => td.innerHTML.toUpperCase().includes(filter)) ? '' : 'none'); }</script> <title>Audit Log Report</title> <style> body { background-color:#E5E4E2; font-family:Monospace; font-size:10pt; } td, th { border:0px solid black; border-collapse:collapse; white-space:pre; } th { color:white; background-color:black; } table, tr, td, th { padding: 2px; margin: 0px; white-space:pre; } tr:nth-child(odd) {background-color: lightgray} table { width:95%;margin-left:5px; margin-bottom:20px; } h2 { font-family:Tahoma; color:#6D7B8D; } .footer { color:green; margin-left:10px; font-family:Tahoma; font-size:8pt; font-style:italic; } #myInput { background-image: url('https://www.w3schools.com/css/searchicon.png'); /* Add a search icon to input */ background-position: 10px 12px; /* Position the search icon */ background-repeat: no-repeat; /* Do not repeat the icon image */ width: 50%; /* Full-width */ font-size: 16px; /* Increase font-size */ padding: 12px 20px 12px 40px; /* Add some padding */ border: 1px solid #ddd; /* Add a grey border */ margin-bottom: 12px; /* Add some space below the input */ } </style> "@ #ITGlue Download starts here If(Get-Module -ListAvailable -Name "ITGlueAPI") {Import-module ITGlueAPI} Else { install-module ITGlueAPI -Force; import-module ITGlueAPI} #Settings IT-Glue logon information Add-ITGlueBaseURI -base_uri $APIEndpoint Add-ITGlueAPIKey $APIKEy $i = 0 #grabbing all orgs for later use. do { $orgs += (Get-ITGlueOrganizations -page_size 1000 -page_number $i).data $i++ Write-Host "Retrieved $($orgs.count) Organisations" -ForegroundColor Yellow }while ($orgs.count % 1000 -eq 0 -and $orgs.count -ne 0) #Grabbing all passwords. Write-Host "Creating backup directory per organisation" -ForegroundColor Green foreach($org in $orgs){ if (!(Test-Path "$($ExportDir)\$($org.attributes.name)")) { $org.attributes.name = $($org.attributes.name).Replace('\W'," ") new-item "$($ExportDir)\$($org.attributes.name)" -ItemType Directory | out-null } } $i = 0 $Passwords = @() Write-Host "Getting passwords" -ForegroundColor Green do { $i++ $PasswordList += (Get-ITGluePasswords -page_size 1000 -page_number $i).data Write-Host "Retrieved $($PasswordList.count) Passwords" -ForegroundColor Yellow }while ($PasswordList.count % 1000 -eq 0 -and $PasswordList.count -ne 0) Write-Host "Processing Passwords. This might take some time." -ForegroundColor Yellow foreach($PasswordItem in $passwordlist){ $Passwords += (Get-ITGluePasswords -show_password $true -id $PasswordItem.id).data } Write-Host "Processed Passwords. Moving on." -ForegroundColor Yellow Write-Host "Getting Flexible Assets" -ForegroundColor Green $FlexAssetTypes = (Get-ITGlueFlexibleAssetTypes -page_size 1000).data foreach($FlexAsset in $FlexAssetTypes){ $i = 0 do { $i++ Write-Host "Getting FlexibleAssets for $($Flexasset.attributes.name)" -ForegroundColor Yellow $FlexibleAssets += (Get-ITGlueFlexibleAssets -filter_flexible_asset_type_id $FlexAsset.id -page_size 1000 -page_number $i).data Write-Host "Retrieved $($FlexibleAssets.count) Flexible Assets" -ForegroundColor Yellow }while ($FlexibleAssets.count % 1000 -eq 0 -and $FlexibleAssets.count -ne 0) } #Generate single HTML file with all passwords. $Passwords.attributes | select-object 'organization-name',name,username,password,url,created-at,updated-at | convertto-html -head $head -precontent '<h1>Password export from IT-Glue</h1><input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for content.." title="Type a query">' | out-file "$($ExportDir)\passwords.html" foreach($FlexibleAsset in $FlexibleAssets.attributes){ $HTMLTop = @" <h1> Flexible Asset Information </h1> <b>organization ID: </b>$($FlexibleAsset."organization-id") <br> <b>organization Name:</b>$($FlexibleAsset."organization-name")<br> <b>name:</b>$($FlexibleAsset.name)<br> <b>created-at </b>$($FlexibleAsset."created-at")<br> <b>updated-at </b>$($FlexibleAsset."updated-at")<br> <b>resource url: </b>$($FlexibleAsset."resource-url")<br> <b>flexible-asset-type-id: </b>$($FlexibleAsset."flexible-asset-type-id")<br> <b>flexible-asset-type-name: </b>$($FlexibleAsset."flexible-asset-type-name")<br> "@ $HTMLTables = $FlexibleAsset.traits | convertto-html -Head $head -PreContent "$HTMLTop <br> <h1> Flexible Asset Traits</h1>" write-host "Ouputting $outputpath" -ForegroundColor Yellow $OutputPath = "$($ExportDir)\$($flexibleasset.'organization-name')" $outputfilename = "$($Flexibleasset.'flexible-asset-type-name') - $($Flexibleasset.name)" $outputfilename = $outputfilename -replace '[\W]','' write-host "Ouputting $outputpath\$outputfilename" -ForegroundColor Yellow $HTMLTables | out-file "$outputpath\$outputfilename HTML.html" $FlexibleAsset.traits | export-csv -path "$outputpath\$outputfilename CSV.csv" -NoTypeInformation }
Script is great and seems to work well. However when I look at the passwords file the passwords column is empty. Anything we can do?
Most likely the “Passwords” permission is not set at the IT-Glue API key side. Make sure the “Passwords” checkbox is marked. Another thing that might be good to know: the script only generates the HTML file with passwords, and nothing else. If you’re looking at the CSV files its correct that these do not contain a password.
Thanks for creating this…I am not getting it to actually output more than one blank html file…get no error messages on run…but doesn’t seem to work.
Creating backup directory
Retrieved 0 Organisations
Creating backup directory per organisation
Getting passwords
Retrieved 0 Passwords
Processing Passwords. This might take some time.
Processed Passwords. Moving on.
Getting Flexible Assets
If I’m in US should I be using the https://api.itglue.com as the API Endpoint…or my custom domain for our IT Glue tenant for the APIEndpoint
nvm bad copypasta
That’s ok! it happens. 🙂 Let me know if there are any more questions.
Pingback: Monitoring and Documenting with PowerShell: End of year review - CyberDrain
Works Great! Thanks Kelvin. All I had to do was change the location to not be the EU data center.