├── DHCP ├── DHCP.flexasset ├── docs │ ├── DHCP_instructions_0.png │ ├── DHCP_instructions_1.png │ └── DHCP_instructions_2.png ├── api_config-DHCP.psd1 ├── README.md └── DHCP.ps1 ├── Python Tooling Scripts ├── .gitignore ├── params_example.json ├── requirements.txt ├── README.md └── copy_flexible_asset_types.py ├── File Shares ├── docs │ ├── FileShares_instructions_0.png │ ├── FileShares_instructions_1.png │ └── FileShares_instructions_2.png ├── api_config-FileShares.psd1 ├── FileShares.flexasset ├── README.md └── FileShares.ps1 ├── Active Directory ├── docs │ ├── activedirectory_instructions_0.png │ ├── activedirectory_instructions_1.png │ └── activedirectory_instructions_2.png ├── ActiveDirectory.flexasset ├── api_config-ActiveDirectory.psd1 ├── Advanced Configuration.md ├── README.md ├── Initialize-ActiveDirectoryFlexAsset.ps1 └── ActiveDirectory.ps1 ├── README.md ├── Cloudflare ├── CloudflareITGlue │ ├── CloudflareITGlue.psm1 │ ├── Private │ │ ├── ITGlueWebRequest.ps1 │ │ ├── CloudflareWebRequest.ps1 │ │ └── CloudflareZoneData.ps1 │ ├── Public │ │ ├── Sync-CloudflareITGlueFlexibleAssets.ps1 │ │ ├── CloudflareITGlueAPIAuth.ps1 │ │ └── New-CloudflareITGlueFlexAssetType.ps1 │ └── CloudflareITGlue.psd1 └── readme.md └── LICENSE /DHCP/DHCP.flexasset: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Python Tooling Scripts/.gitignore: -------------------------------------------------------------------------------- 1 | .venv/ 2 | params.json 3 | -------------------------------------------------------------------------------- /DHCP/docs/DHCP_instructions_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itglue/automation/HEAD/DHCP/docs/DHCP_instructions_0.png -------------------------------------------------------------------------------- /DHCP/docs/DHCP_instructions_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itglue/automation/HEAD/DHCP/docs/DHCP_instructions_1.png -------------------------------------------------------------------------------- /DHCP/docs/DHCP_instructions_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itglue/automation/HEAD/DHCP/docs/DHCP_instructions_2.png -------------------------------------------------------------------------------- /File Shares/docs/FileShares_instructions_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itglue/automation/HEAD/File Shares/docs/FileShares_instructions_0.png -------------------------------------------------------------------------------- /File Shares/docs/FileShares_instructions_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itglue/automation/HEAD/File Shares/docs/FileShares_instructions_1.png -------------------------------------------------------------------------------- /File Shares/docs/FileShares_instructions_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itglue/automation/HEAD/File Shares/docs/FileShares_instructions_2.png -------------------------------------------------------------------------------- /Active Directory/docs/activedirectory_instructions_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itglue/automation/HEAD/Active Directory/docs/activedirectory_instructions_0.png -------------------------------------------------------------------------------- /Active Directory/docs/activedirectory_instructions_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itglue/automation/HEAD/Active Directory/docs/activedirectory_instructions_1.png -------------------------------------------------------------------------------- /Active Directory/docs/activedirectory_instructions_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itglue/automation/HEAD/Active Directory/docs/activedirectory_instructions_2.png -------------------------------------------------------------------------------- /DHCP/api_config-DHCP.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | org_id = '' 3 | flexible_asset_type_id = '' 4 | 5 | key_name_ScopeName = '' 6 | key_name_Server = '' 7 | key_name_ScopeBounds = '' 8 | } -------------------------------------------------------------------------------- /Python Tooling Scripts/params_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "SourceAccountAPIKey": "original_account_api_key", 3 | "APIUrl": "api_region_endpoint", 4 | "TargetAccountAPIKEy": "copy_to_account_api_key" 5 | } 6 | -------------------------------------------------------------------------------- /Python Tooling Scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2018.11.29 2 | chardet==3.0.4 3 | idna==2.8 4 | itglue==0.1.2 5 | requests==2.21.0 6 | urllib3==1.24.1 7 | certifi==2018.11.29 8 | chardet==3.0.4 9 | idna==2.8 10 | itglue==0.1.3 11 | requests==2.21.0 12 | urllib3==1.24.1 13 | -------------------------------------------------------------------------------- /File Shares/api_config-FileShares.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | org_id = '' 3 | flexible_asset_type_id = '' 4 | 5 | key_name_ShareName = '' 6 | key_name_ShareDescription = '' 7 | key_name_Server = '' 8 | key_name_SharePath = '' 9 | key_name_DiskPath = '' 10 | key_name_Permissions = '' 11 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # automation 2 | 3 | A place for IT Glue's user community to learn ways of automating their documentation. 4 | 5 | IT Glue API documentation: 6 | - [Developer Documentation](https://api.itglue.com/developer/) 7 | - [Getting started with the IT Glue API](https://kb.itglue.com/hc/en-us/articles/236404927) 8 | - [Pagination in the IT Glue API](https://kb.itglue.com/hc/en-us/articles/115001445108) 9 | - [Sorting and filtering in the IT Glue API](https://kb.itglue.com/hc/en-us/articles/115004332688) 10 | -------------------------------------------------------------------------------- /Cloudflare/CloudflareITGlue/CloudflareITGlue.psm1: -------------------------------------------------------------------------------- 1 | $ModuleBase = Get-Module CloudflareITGlue -ListAvailable | ForEach-Object ModuleBase 2 | 3 | if (Test-Path "$ModuleBase\$env:username.auth") { 4 | Write-Host "CloudflareITGlue: Auth detected for $env:username" -ForegroundColor Green 5 | $Auth = Import-Csv "$ModuleBase\$env:username.auth" 6 | $Global:CloudflareAPIEmail = $Auth.CloudflareEmail 7 | $Global:CloudflareAPIKey = ($Auth.CloudflareAPIKey | ConvertTo-SecureString) 8 | $Global:ITGlueAPIKey = ($Auth.ITGlueAPIKey | ConvertTo-SecureString) 9 | } 10 | 11 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 12 | -------------------------------------------------------------------------------- /File Shares/FileShares.flexasset: -------------------------------------------------------------------------------- 1 | Name: File Server/Share 2 | Kind: Header 3 | 4 | Name: Share Name 5 | Kind: Text 6 | Hint: e.g. Sales 7 | Checkboxes: Required, Show in list, Use for title 8 | 9 | Name: Share Description 10 | Kind: Text 11 | Hint: e.g. Sales Information 12 | Checkboxes: Required, Show in list 13 | 14 | Name: Servers 15 | Kind: Tag 16 | Type: Configurations 17 | Hint: Tag servers delivering this share 18 | Checkboxes: Show in list 19 | 20 | Name: Mapped Drive 21 | Kind: Text 22 | Hint: e.g. S:\ 23 | Checkboxes: Show in list, Use for title 24 | 25 | Name: Share Path 26 | Kind: Text 27 | Hint: e.g. \\SERVER\Share 28 | Checkboxes: Show in list 29 | 30 | Name: Disk Path 31 | Kind: Text 32 | Hint: e.g. D:\Share 33 | Checkboxes: Show in list 34 | 35 | Name: Share Permissions 36 | Kind: Textbox 37 | Hint: What members have access? 38 | Checkboxes: Show in list -------------------------------------------------------------------------------- /Active Directory/ActiveDirectory.flexasset: -------------------------------------------------------------------------------- 1 | Name: Forest Name 2 | Kind: Text 3 | Hint: Full forest name - e.g. domain.com 4 | Checkboxes: Required, Show in List 5 | 6 | Name: Domain Full Name 7 | Kind: Text 8 | Hint: Full Active Directory domain name - e.g. corp.domain.com 9 | Checkboxes: Required, Show in list, Use for title 10 | 11 | Name: Domain Short Name 12 | Kind: Text 13 | Hint: Short Active Directory domain name - e.g. CORP 14 | Checkboxes: Required, Show in list, Use for title 15 | 16 | Name: AD Level 17 | Kind: Select 18 | Hint: Domain Functional Level 19 | Options: 2000, 2003, 2008, 2008 R2, 2012, 2012 R2 20 | Checkboxes: Required, Show in list 21 | 22 | Name: Schema Master 23 | Kind: Tag 24 | Type: Configurations 25 | Checkboxes: Required, Show in list 26 | 27 | Name: Domain Naming Master 28 | Kind: Tag 29 | Type: Configurations 30 | Checkboxes: Required, Show in list 31 | 32 | Name: Relative ID (RID) Master 33 | Kind: Tag 34 | Type: Configurations 35 | Checkboxes: Required, Show in list 36 | 37 | Name: PDC Emulator Master 38 | Kind: Tag 39 | Type: Configurations 40 | Checkboxes: Required, Show in list 41 | 42 | Name: Infrastructure Master 43 | Kind: Tag 44 | Type: Configurations 45 | Checkboxes: Required, Show in list 46 | 47 | Name: Global Catalog Servers (Domain Controllers) 48 | Kind: Tag 49 | Type: Configurations 50 | Checkboxes: Required, Show in list 51 | -------------------------------------------------------------------------------- /Cloudflare/CloudflareITGlue/Private/ITGlueWebRequest.ps1: -------------------------------------------------------------------------------- 1 | function New-ITGlueWebRequest { 2 | param( 3 | [Parameter(Mandatory = $true)][string]$Endpoint, 4 | [ValidateSet('GET', 'POST', 'PATCH', 'DELETE')][string]$Method = 'GET', 5 | [string]$Body = $null, 6 | [int]$ResultsPerPage = 50, 7 | [int]$PageNumber = 1 8 | ) 9 | 10 | if ($ITGlueAPIKey) { 11 | try { 12 | $APIKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($ITGlueAPIKey)) 13 | } 14 | catch { 15 | Write-Warning 'New-ITGlueWebRequest: Unable to decrypt auth info' 16 | Write-Warning 'Run Add-CloudflareITGlueAPIAuth to re-add' 17 | break 18 | } 19 | } 20 | else { 21 | Write-Warning 'Run Add-CloudflareITGlueAPIAuth to add authorization info' 22 | break 23 | } 24 | 25 | $RequestParams = @{ 26 | Uri = 'https://api.itglue.com/' + $Endpoint + "?page[size]=$ResultsPerPage&page[number]=$PageNumber" 27 | Method = $Method 28 | Headers = @{ 29 | 'x-api-key' = $APIKey 30 | 'Content-Type' = 'application/vnd.api+json' 31 | } 32 | } 33 | if ($Body) {$RequestParams.Body = $Body} 34 | 35 | try { 36 | $Request = Invoke-RestMethod @RequestParams 37 | 38 | if ($PageNumber -lt $Request.meta.'total-pages') { 39 | $PageNumber++ 40 | New-ITGlueWebRequest -Endpoint $Endpoint -Body $Body -ResultsPerPage $ResultsPerPage -PageNumber $PageNumber 41 | } 42 | $APIKey = $null 43 | $RequestParams = $null 44 | return $Request 45 | } 46 | catch { 47 | Write-Warning "Something went wrong with ITGlue request:`n$_" 48 | $APIKey = $null 49 | $RequestParams = $null 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Active Directory/api_config-ActiveDirectory.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | 3 | <# 4 | 5 | The following variables are specific to the current flex asset and organization, respectively. 6 | 7 | If no $org_id is explicitely defined, running the ActiveDirectory.ps1 script with the -organization 8 | parameter will make an attempt at matching that organization name with the names present in IT Glue. An 9 | exact match is required. If it is found, this configuration file will automatically be updated with the 10 | corresponding $org_id 11 | 12 | The $flexible_asset_type_id corresponds to the flexible asset type that represents what an "Active Directory" flex 13 | asset should look like for IT Glue. Please run `(Get-ITGlueFlexibleAssetTypes).data` and find the type id 14 | corresponding to your account's flexible asset type for Active Directory. Additionally, ensure that the proper 15 | fields are present in that template. 16 | 17 | #> 18 | 19 | 20 | # REQUIRED 21 | org_id = "" 22 | # REQUIRED 23 | flexible_asset_type_id = "" 24 | 25 | 26 | 27 | <# 28 | 29 | The following fields correspond to the "api" names of the fields needing to be filled out for an Active Directory 30 | flexible asset. These names are found using the `Get-ITGlueFlexibleAssetFields -flex_asset_id ` command, replacing 31 | `` with whatever the flex_asset_id is that you specified above in this configuration file. The data that is returned 32 | by the `Get-ITGlueFlexibleAssetFields` command outlines the 'name-key's that need to be entered here. Please review 33 | the README.md file for more information on how to fill this out. 34 | 35 | 36 | #> 37 | 38 | key_name_ADForestName = "" 39 | key_name_ADFunctionalLevel = "" 40 | key_name_DomainName = "" 41 | key_name_DomainShortName = "" 42 | key_name_SchemaMaster = "" 43 | key_name_DomainNamingMaster = "" 44 | key_name_RIDMaster = "" 45 | key_name_PDCEmulator = "" 46 | key_name_InfrastructureMaster = "" 47 | key_name_GlobalCatalogServers = "" 48 | 49 | 50 | } -------------------------------------------------------------------------------- /Cloudflare/CloudflareITGlue/Private/CloudflareWebRequest.ps1: -------------------------------------------------------------------------------- 1 | function New-CloudflareWebRequest { 2 | param( 3 | [Parameter(Mandatory = $true)][string]$Endpoint, 4 | [ValidateSet('GET', 'POST', 'PUT', 'PATCH', 'DELETE')][string]$Method = 'GET', 5 | [string]$Body = $null, 6 | [int]$ResultsPerPage = 50, 7 | [int]$PageNumber = 1 8 | ) 9 | 10 | if ($CloudflareAPIKey) { 11 | try { 12 | $APIKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($CloudflareAPIKey)) 13 | } 14 | catch { 15 | Write-Warning 'New-CloudflareWebRequest: Unable to decrypt auth info' 16 | Write-Warning 'Run Add-CloudflareITGlueAPIAuth to re-add' 17 | break 18 | } 19 | } 20 | else { 21 | Write-Warning 'Run Add-CloudflareITGlueAPIAuth to add authorization info' 22 | break 23 | } 24 | 25 | $RequestParams = @{ 26 | Uri = 'https://api.cloudflare.com/client/v4/' + $Endpoint + "?per_page=$ResultsPerPage&page=$PageNumber" 27 | Method = $Method 28 | Headers = @{ 29 | 'X-Auth-Key' = $APIKey 30 | 'X-Auth-Email' = $CloudflareAPIEmail 31 | 'Content-Type' = 'application/json' 32 | } 33 | } 34 | if ($Body) {$RequestParams.Body = $Body} 35 | 36 | try { 37 | Start-Sleep -Milliseconds 275 38 | $Request = Invoke-RestMethod @RequestParams 39 | Start-Sleep -Milliseconds 275 40 | #RateLimit = 1200 requests/5 min but still getting gateway timeouts @ 300ms+ 41 | 42 | if ($PageNumber -lt $Request.result_info.total_pages) { 43 | $PageNumber++ 44 | New-CloudflareWebRequest -Endpoint $Endpoint -ResultsPerPage $ResultsPerPage -PageNumber $PageNumber 45 | } 46 | $APIKey = $null 47 | $RequestParams = $null 48 | return $Request 49 | } 50 | catch { 51 | Write-Warning "Something went wrong with Cloudflare request:`n$_" 52 | $APIKey = $null 53 | $RequestParams = $null 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Python Tooling Scripts/README.md: -------------------------------------------------------------------------------- 1 | ## Tooling Scripts 2 | All Python scripts for small tooling purposes using IT Glue API will 3 | reside in this folder 4 | 5 | ## Requirements 6 | You will need Python >3.6 installed in your system 7 | 8 | ## Getting started 9 | 10 | #### 1. Python installation 11 | First, you will need to make sure you have Python 3.6 with setuptools, 12 | pip and venv installed. 13 | You can follow the steps [here](http://docs.python-guide.org/en/latest/starting/installation/) 14 | to install Python 3 in your system. 15 | 16 | #### 2. Creating virtual environment 17 | Once you have Python 3.6 installed, create the Python 18 | virtual environment in the root of this project with the following command: 19 | 20 | python3 -m venv .venv 21 | 22 | 23 | #### 3. Activate virtual environment 24 | To activate the virtual environment, use the command below that corresponds to your OS. 25 | ##### Unix or MacOS 26 | 27 | source .venv/bin/activate 28 | 29 | ##### Windows 30 | 31 | .venv\Scripts\activate.bat 32 | 33 | 34 | #### 4. Install dependancies 35 | Now we need to install the script dependancies using pip. 36 | 37 | pip install -r requirements.txt 38 | 39 | ## Copy Flexible Asset Types Between IT Glue Accounts 40 | ### Requirements 41 | - Both accounts must reside in the same region (in North America or Europe) 42 | - Valid API Keys from both accounts 43 | 44 | ### 1. Create `params.json` file 45 | Copy the `params_example.json` to a file 46 | named `params.json` at the same folder level. 47 | 48 | - `SourceAccountAPIKey` - This is the API Key of the IT Glue account from which 49 | the flexible asset types are copied 50 | - `APIUrl` - For North American accounts, use `https://api.itglue.com` and for 51 | EU accounts, use `https://api.eu.itglue.com` 52 | - `TargetAccountAPIKey` - This is the API Key of the IT Glue account to which 53 | flexible asset types are copied 54 | 55 | 56 | ### 2. Run command 57 | To initiate copying of the flexible asset types, run 58 | ``` 59 | python copy_flexible_asset_types.py 60 | ``` 61 | 62 | 63 | ### 3. Notes 64 | * If there are flexible asset types with the same name in the target account as the 65 | types in the source account, the script will not update the existing types in 66 | the target account. 67 | * Console output will indicate if any of the flexible asset types encounter an 68 | IT Glue API error during the copy. Please fix error prior to re-running the script. 69 | * Re-running the script will not duplicate the copying of flexible asset types. 70 | * Order of Flexible asset type copying is: 71 | 1. Types without any flexible asset type tag fields 72 | 1. Types with flexible asset type tag fields 73 | 1. Types with *only* flexible asset type tag fields 74 | * If there are cyclical dependency between types and their tags, it will not create the tag field that creates a circle dependency 75 | -------------------------------------------------------------------------------- /Cloudflare/CloudflareITGlue/Public/Sync-CloudflareITGlueFlexibleAssets.ps1: -------------------------------------------------------------------------------- 1 | function Sync-CloudflareITGlueFlexibleAssets { 2 | param( 3 | [string]$FlexAssetType = 'Cloudflare DNS' 4 | ) 5 | 6 | $Progress = 0 7 | $ZoneDataArray = Get-CloudflareZoneDataArray 8 | $FlexAssetTypeId = New-ITGlueWebRequest -Endpoint 'flexible_asset_types' -Method 'GET' | ForEach-Object data | Where-Object {$_.attributes.name -eq $FlexAssetType} | ForEach-Object id 9 | 10 | foreach ($ZoneData in $ZoneDataArray) { 11 | Write-Progress -Activity 'ITGlueAPI' -Status 'Syncing Flexible Assets' -CurrentOperation $ZoneData.name -PercentComplete ($Progress / ($ZoneDataArray | Measure-Object | foreach-object count) * 100) -Id 2 12 | 13 | $TempFile = New-TemporaryFile 14 | $ZoneData.ZoneFileData | Out-file $TempFile -Force -Encoding utf8 15 | $Base64ZoneFile = ([System.Convert]::ToBase64String([System.IO.File]::ReadAllBytes($TempFile))) 16 | Remove-Item $TempFile -Force 17 | $Body = @{ 18 | data = @{ 19 | 'type' = 'flexible-assets' 20 | 'attributes' = @{ 21 | 'organization-id' = $ZoneData.ITGOrg 22 | 'flexible-asset-type-id' = $FlexAssetTypeId 23 | 'traits' = @{ 24 | 'name' = $ZoneData.Name 25 | 'last-sync' = $ZoneData.SyncDate 26 | 'nameservers' = $ZoneData.CfNameServers -join '
' 27 | 'status' = $ZoneData.Status 28 | 'zone-file' = @{ 29 | 'content' = $Base64ZoneFile 30 | 'file_name' = "$($ZoneData.Name).txt" 31 | } 32 | 'dns-records' = $ZoneData.RecordsHtml 33 | 'domain-tracker' = $ZoneData.DomainTracker 34 | } 35 | } 36 | } 37 | } 38 | $Body = $Body | ConvertTo-Json -Depth 4 39 | $FlexAssets = New-ITGlueWebRequest -Endpoint "flexible_assets?filter[flexible_asset_type_id]=$FlexAssetTypeId&filter[organization_id]=$($ZoneData.ITGOrg)" -Method 'GET' | ForEach-Object data 40 | $PatchId = $null 41 | 42 | foreach ($FlexAsset in $FlexAssets) { 43 | if ($FlexAsset.attributes.traits.name -eq $ZoneData.name) { 44 | $PatchId = $FlexAsset.id 45 | } 46 | } 47 | if ($PatchId) { 48 | New-ITGlueWebRequest -Endpoint "flexible_assets/$PatchId" -Method 'PATCH' -Body $Body 49 | } 50 | else { 51 | New-ITGlueWebRequest -Endpoint 'flexible_assets' -Method 'POST' -Body $Body 52 | } 53 | $Progress++ 54 | } 55 | Write-Progress -Activity 'ITGlueAPI' -Status 'Syncing Flexible Assets' -PercentComplete 100 -Id 2 56 | } 57 | -------------------------------------------------------------------------------- /Active Directory/Advanced Configuration.md: -------------------------------------------------------------------------------- 1 | This document outlines the steps involved if you wish to utilize an existing Flexible Asset Type with the script, rather than creating a new one using the `Initialize-ActiveDirectoryFlexAsset.ps1` script. 2 | 3 | # Instructions 4 | 5 | This script makes use of a configuration file to hold neccessary data that the API needs to be able to create and modify flexible assets. In the simplest form, that configuration file looks like: 6 | 7 | ```posh 8 | @{ 9 | flex_asset_id = '' 10 | org_id = '' 11 | flexible_asset_type_id = '' 12 | 13 | key_name_ADForestName = '' 14 | key_name_ADFunctionalLevel = '' 15 | key_name_DomainName = '' 16 | key_name_DomainShortName = '' 17 | key_name_SchemaMaster = '' 18 | key_name_DomainNamingMaster = '' 19 | key_name_RIDMaster = '' 20 | key_name_PDCEmulator = '' 21 | key_name_InfrastructureMaster = '' 22 | key_name_GlobalCatalogServers = '' 23 | 24 | 25 | } 26 | ``` 27 | 28 | The `flexible_asset_type_id` and all `key_name_` variables have to be filled out, however this is a one-time process, as these values are the same across your entire IT Glue account (and all organizations under it). To start with, let's find out the `flexible_asset_type_id` by running the following code: 29 | 30 | ```posh 31 | Import-Module ITGlueAPI 32 | 33 | $output = Get-ITGlueFlexibleAssetTypes 34 | $output.data 35 | ``` 36 | 37 | Your screen should look like this: 38 | 39 | ![](docs/activedirectory_instructions_0.png) 40 | 41 | Find the `id` that corresponds to the Active Directory flex asset type. Now that we have found it, fill it out in your config file. 42 | 43 | Next, let's find out what to put for the `key_name_` variables by running the following code to see what fields are attributed to the Active Directory flex asset type: 44 | 45 | ```posh 46 | $output = Get-ITGlueFlexibleAssetFields -flexible_asset_type_id #insert your flex asset type id 47 | $output.data.attributes 48 | ``` 49 | 50 | ![](docs/activedirectory_instructions_1.png) 51 | 52 | Each field should now be listed. In specific, the attribute we are looking for is called `name-key`. The data in this field is what we need to fill out our config file. For each element in the config file, fill out the corresponding `name-key` of the field returned by the aforementioned PowerShell commands. 53 | 54 | To make it a bit easier, feel free to list all of the `name-key` values in one shot, just be careful to get the correct ones: 55 | 56 | ```posh 57 | $output.data.attributes.'name-key' 58 | ``` 59 | 60 | ![](docs/activedirectory_instructions_2.png) 61 | 62 | For our example shown in the screenshots, the following is what we would expect our `key_name_` elements to look like in our config file: 63 | 64 | ```posh 65 | @{ 66 | flex_asset_id = '' 67 | org_id = '' 68 | flexible_asset_type_id = 'xxxxx' 69 | 70 | key_name_ADForestName = 'forest-name' 71 | key_name_ADFunctionalLevel = 'functional-level' 72 | key_name_DomainName = 'domain-name' 73 | key_name_DomainShortName = 'domain-short-name' 74 | key_name_SchemaMaster = 'schema-master' 75 | key_name_DomainNamingMaster = 'domain-naming-master' 76 | key_name_RIDMaster = 'rid-master' 77 | key_name_PDCEmulator = 'pdc-emulator' 78 | key_name_InfrastructureMaster = 'infrastructure-master' 79 | key_name_GlobalCatalogServers = 'global-catalog-servers' 80 | 81 | 82 | } 83 | ``` 84 | 85 | Once you are done, save your configuration file in the same directory as your script and make sure to pass the name of the file into the script using the `-api ` parameter if you want your script to automatically send data to IT Glue. -------------------------------------------------------------------------------- /Cloudflare/CloudflareITGlue/Public/CloudflareITGlueAPIAuth.ps1: -------------------------------------------------------------------------------- 1 | function Add-CloudflareITGlueAPIAuth { 2 | if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { 3 | Write-Host 'Add/removing API Auth require admin access' -ForegroundColor Yellow 4 | } 5 | else { 6 | [pscredential]$CloudflareCredentials = $Host.UI.PromptForCredential('Cloudflare API Authentication', "User name: Cloudflare Email`r`nPassword: Cloudflare API Key", '', '') 7 | [pscredential]$ITGCredentials = $Host.UI.PromptForCredential('ITGlue API Authentication', 'Password: ITGlue API Key', 'ITGlue', '') 8 | $Global:CloudflareAPIEmail = $CloudflareCredentials.username 9 | $Global:CloudflareAPIKey = $CloudflareCredentials.Password 10 | $Global:ITGlueAPIKey = $ITGCredentials.Password 11 | 12 | if (!$CloudflareAPIEmail -or !$CloudflareAPIKey -or !$ITGlueAPIKey) { 13 | Write-Host 'Cancelled' -ForegroundColor Yellow 14 | break 15 | } 16 | if ($CloudflareAPIEmail -notmatch "\A[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z") { 17 | Write-Host 'Invalid email address format' -ForegroundColor Yellow 18 | break 19 | } 20 | if (!$CloudflareCredentials.GetNetworkCredential().Password -or !$ITGCredentials.GetNetworkCredential().Password) { 21 | Write-Warning 'API key(s) not entered' 22 | break 23 | } 24 | $Credentials = @{ 25 | CloudflareEmail = $CloudflareAPIEmail 26 | CloudflareAPIKey = ($CloudflareAPIKey | ConvertFrom-SecureString) 27 | ITGlueAPIKey = ($ITGlueAPIKey | ConvertFrom-SecureString) 28 | } 29 | $Auth = @() 30 | $Auth += [pscustomobject]$Credentials 31 | $ModuleBase = Get-Module CloudflareITGlue | ForEach-Object ModuleBase 32 | 33 | $Auth | Export-Csv "$ModuleBase\$env:username.auth" -NoTypeInformation -Force 34 | } 35 | } 36 | 37 | function Get-CloudflareITGlueAPIAuth { 38 | if (Test-Path "$ModuleBase\$env:username.auth") { 39 | Write-Host 'Auth file detected' -ForegroundColor Green 40 | $Auth = Import-Csv "$ModuleBase\$env:username.auth" 41 | 42 | try { 43 | $cfkey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($($Auth.CloudflareAPIKey | ConvertTo-SecureString))) 44 | $itgkey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($($Auth.ITGlueAPIKey | ConvertTo-SecureString))) 45 | $cfkeyhalf = [int]($cfkey | Measure-Object -Character | ForEach-Object Characters) / 2 46 | $itgkeyhalf = [int]($itgkey | Measure-Object -Character | ForEach-Object Characters) / 2 47 | Write-Host "Cloudflare Email: $($Auth.CloudflareEmail)" 48 | Write-Host "Cloudflare API Key: $($cfkey.Substring(0,$cfkeyhalf))********************" -ErrorAction Ignore 49 | Write-Host "ITGlue API Key: $($itgkey.Substring(0,$itgkeyhalf))********************`n" -ErrorAction Ignore 50 | $cfkey = $null 51 | $itgkey = $null 52 | } 53 | catch { 54 | Write-Warning 'Invalid format or unable to decrypt' 55 | Write-Warning 'Run Add-CloudflareITGlueAPIAuth to re-add auth info for the current account' 56 | $cfkey = $null 57 | $itgkey = $null 58 | } 59 | } 60 | else { 61 | Write-Host "No auth detected for $env:username" -ForegroundColor Yellow 62 | } 63 | } 64 | 65 | function Remove-CloudflareITGlueAPIAuth { 66 | if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { 67 | Write-Host 'Add/removing API Auth require admin access' -ForegroundColor Yellow 68 | } 69 | else { 70 | if (Test-Path "$ModuleBase\$env:username.auth") { 71 | Remove-Item "$ModuleBase\$env:username.auth" -Force 72 | } 73 | else { 74 | Write-Host 'Not added' -ForegroundColor Yellow 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Active Directory/README.md: -------------------------------------------------------------------------------- 1 | # Active Directory Automation 2 | 3 | Getting accurate information for Active Directory environments is crucial to properly support your clients. Let's look at a script that can automate the discovery of your AD environment, create a Flex Asset in IT Glue, *and* continue to update that same flex asset by simply re-running the script on a scheduled basis. 4 | 5 | ## Setup Instructions 6 | 7 | :warning: If you intend to use this script's API functionality, make sure you have installed the [IT Glue PowerShell Module](https://github.com/itglue/powershellwrapper) 8 | 9 | :warning: Make sure your Active Directory flexible asset type in IT Glue has fields corresponding to the ones outlined in `ActiveDirectory.flexasset`, as that is the data that this script is capable of finding. 10 | 11 | This script makes use of a configuration file to hold neccessary data that the API needs to be able to create and modify flexible assets. In the simplest form, that configuration file looks like: 12 | 13 | ```posh 14 | @{ 15 | flex_asset_id = '' 16 | org_id = '' 17 | flexible_asset_type_id = '' 18 | 19 | key_name_ADForestName = '' 20 | key_name_ADFunctionalLevel = '' 21 | key_name_DomainName = '' 22 | key_name_DomainShortName = '' 23 | key_name_SchemaMaster = '' 24 | key_name_DomainNamingMaster = '' 25 | key_name_RIDMaster = '' 26 | key_name_PDCEmulator = '' 27 | key_name_InfrastructureMaster = '' 28 | key_name_GlobalCatalogServers = '' 29 | 30 | 31 | } 32 | ``` 33 | 34 | In order to get started easily, an `Initialize-ActiveDirectoryFlexAsset.ps1` script has been created. Running this script will automatically create a new Flexible Asset Template in your IT Glue account and generate a `config.psd1` configuration file. 35 | 36 | If you wish to modify an existing flexible asset type rather than creating a new one, please see the [Advanced Configuration](https://github.com/itglue/automation/blob/master/Active%20Directory/Advanced%20Configuration.md) instructions. 37 | 38 | :warning: Although this configuration is a one-time process, the `$org_id` parameter in the configuration file must be updated for each organization you wish to run the script for. You can find this organization id by navigating to the organization page in IT Glue and looking at the URL in your web browser. If the page is `https://subdomain.itglue.com/1234567`, the organization id is `1234567`. 39 | 40 | Once you are done, save your configuration file in the same directory as your script and make sure to pass the name of the file into the script using the `-api ` parameter if you want your script to automatically send data to IT Glue. 41 | 42 | ## Running the script for the first time 43 | 44 | After following the setup instructions, it is time to run your script. There are a few things to note: 45 | 46 | :warning: This script assumes that the servers it tags are in IT Glue as Configurations and that there is an exact name match. For example, if a Global Catalog server is named "East-DC-2", this script expects to have a configuration item in IT Glue under the current organization that has a name of "East-DC-2". If this is not the case, the script will fail to appropriately create or update the flex asset. 47 | 48 | Once your configuration file is appropriately set up, all you need to do is run the script with `.\ActiveDirectory.ps1 -api api_config-ActiveDirectory.psd1` and the script will take care of the rest, including auto-updating the config document with the flexible asset id that is created. 49 | 50 | NOTE: Every organization in IT Glue has a specific id attached to it. If you are unaware of the id for the organization or client you are getting AD information for, you are welcome to use the scripts `-organization ` parameter. For example, if you are running this script at a client who's name in IT Glue is `Happy Frog`, you can run the script with `.\ActiveDirectory.ps1 -api api_config-ActiveDirectory.psd1 -organization "Happy Frog"`, and the script will automatically find the organization id. Do note that it looks for an **exact** match for the organization name. 51 | 52 | After you have run the script for the first time, you are welcome to re-run it as often as you please to capture any changes and update the flex asset in IT Glue. Since the flex asset id is automatically updated in the config file, this script will be able to handle everything without manual intervention. For example, you might want to set up a scheduled task to run `.\ActiveDirectory.ps1 -api api_config-ActiveDirectory.psd1` on a weekly or monthly basis to make sure any changes are properly reflected in IT Glue. 53 | 54 | ---- 55 | 56 | :heart: Documentation Automation! -------------------------------------------------------------------------------- /Cloudflare/readme.md: -------------------------------------------------------------------------------- 1 | # CloudflareITGlue Powershell Module 2 | 3 | ## What does this do 4 | 5 | - Sync Cloudflare DNS Zones to ITGlue Client Organizations as Flex Assets 6 | 7 | ![screenshot](https://user-images.githubusercontent.com/43423017/48573233-6e7f4700-e8c0-11e8-8dd1-793e06620e96.png) 8 | 9 | >**Name:** Name of the Cloudflare DNS Zone 10 | >**Last Sync:** Timestamp when flex asset is created/updated 11 | >**Nameservers:** Nameservers designated by Cloudflare 12 | >**Status:** Status of the Cloudflare DNS Zone 13 | >**Zone File:** BIND format zone file 14 | >**Domain Tracker:** Domain Tracker Tag 15 | >**DNS Records:** Table of all DNS records in the zone and a link to the zone page in Cloudflare 16 | >**Revisions:** Flex assets contain revision history by nature 17 | 18 | ## How it works 19 | 20 | - Configure 21 | - Schedule the sync command to run at a desired interval 22 | 23 | ## Configuration 24 | 25 | [Installing the module](#installing-the-module) 26 | [API Authorization](#api-authorization) 27 | [Creating the ITGlue Flex Asset Type](#creating-the-itglue-flex-asset-type) 28 | 29 | ### Installing the module 30 | 31 | Copy the CloudflareITGlue module folder into the Powershell module directory 32 | >`C:\Program Files\WindowsPowerShell\Modules\CloudflareITGlue` 33 | 34 | ### API Authorization 35 | 36 | #### Obtain API keys 37 | 38 | - Cloudflare 39 | - Login to Cloudflare. 40 | - Go to **My Profile**. 41 | - Scroll down to **API Keys** and locate _Global API Key_. 42 | - Select **API Key**. 43 | 44 | - ITGlue 45 | - Login to ITGlue. 46 | - Select the **Account** tab. 47 | - Select the **API Keys** tab. 48 | - Click the **+** symbol to add a new API key. 49 | - **Enter Name**. 50 | - Select **Generate API Key** 51 | 52 | #### Add authorization 53 | 54 | ```powershell 55 | Add-CloudflareITGlueAPIAuth 56 | ``` 57 | 58 | >This will prompt you for your API keys and Cloudflare email. The API keys will be encrypted with your user account and stored in the module directory. Requires elevated permissions for file creation. 59 | 60 | #### Viewing/Removing authorization info 61 | 62 | ```powershell 63 | Get-CloudflareITGlueAPIAuth 64 | Remove-CloudflareITGlueAPIAuth 65 | ``` 66 | 67 | >Use these to view/delete the auth that's been entered. 68 | >API keys are not shown in full. Removal requires elevated permissions to delete file. 69 | 70 | ### Creating the ITGlue Flex Asset Type 71 | 72 | ```powershell 73 | New-CloudflareITGlueFlexAssetType 74 | ``` 75 | 76 | >This will create a new Flex Asset Type in ITGlue called **Cloudflare DNS**. 77 | >Customize your ITGlue sidebar in the **Account > Settings > General > Customize Sidebar** section. 78 | >If you need to use a different name there is an optional parameter: 79 | >`New-CloudflareITGlueFlexAssetType -Name 'My Cloudflare DNS'` 80 | 81 | ## Usage 82 | 83 | ```powershell 84 | Sync-CloudflareITGlueFlexibleAssets 85 | ``` 86 | 87 | >This command will match Cloudflare zones to ITGlue orgs using the Domain Tracker then sync the zones as flex assets to their respective organizations. 88 | >Cloudflare zones that are not in the Domain Tracker will be output to the console. 89 | >If you used a custom name for the flex asset type, you'll also need to pass it to the sync command via the optional FlexAssetType parameter: 90 | >`Sync-CloudflareITGlueFlexibleAssets -FlexAssetType 'My Cloudflare DNS'` 91 | 92 | Set this up to run at an interval of your choosing however you like. 93 | 94 | - Heres a quick Powershell script you can use to create a scheduled task: 95 | 96 | >```powershell 97 | >$Action = New-ScheduledTaskAction -Execute 'Powershell.exe' ` 98 | > -Argument '-NoProfile -WindowStyle Hidden -Command "& Sync-CloudflareITGlueFlexibleAssets"' 99 | >$Trigger = New-ScheduledTaskTrigger -Daily -At 8am 100 | >$Principal = New-ScheduledTaskPrincipal -UserID '%username%' -LogonType S4U 101 | >Register-ScheduledTask -TaskName 'Sync zones' -Action $Action -Trigger $Trigger -Principal $Principal 102 | ># Be sure you've added auth info for %username% 103 | >``` 104 | 105 | ## References 106 | 107 | [Invoke-RestMethod Documentation](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod/) 108 | [ITGlue API Documentation](https://api.itglue.com/developer/) 109 | [Cloudflare API Documentation](https://api.cloudflare.com/) 110 | >On Cloudflare Rate Limiting: "The Cloudflare API sets a maximum of 1,200 requests in a five minute period." 111 | >You may still see the odd gateway timeout even though the rate limit is accounted for. 112 | -------------------------------------------------------------------------------- /DHCP/README.md: -------------------------------------------------------------------------------- 1 | # IPv4 DHCP Documentation Automation 2 | 3 | Getting accurate information for DHCP is crucial to properly support your clients. Let's look at a script that can automate the discovery of your DHCP scopes and create a Flex Asset in IT Glue to store the scope information. 4 | 5 | ## Setup Instructions 6 | 7 | :warning: If you intend to use this script's API functionality, make sure you have installed the [IT Glue PowerShell Module](https://github.com/itglue/powershellwrapper) 8 | 9 | :warning: Make sure your DHCP flexible asset type in IT Glue has fields corresponding to the ones outlined in `DHCP.flexasset`, as that is the data that this script is capable of finding. 10 | 11 | This script makes use of a configuration file to hold neccessary data that the API needs to be able to create and modify flexible assets. In the simplest form, that configuration file looks like: 12 | 13 | ```posh 14 | @{ 15 | org_id = '' 16 | flexible_asset_type_id = '' 17 | 18 | key_name_ScopeName = '' 19 | key_name_Server = '' 20 | key_name_ScopeBounds = '' 21 | } 22 | ``` 23 | 24 | The `flexible_asset_type_id` and all `key_name_` variables have to be filled out, however this is a one-time process, as these values are the same across your entire IT Glue account (and all organizations under it). To start with, let's find out the `flexible_asset_type_id` by running the following code: 25 | 26 | ```posh 27 | Import-Module ITGlueAPI 28 | 29 | $output = Get-ITGlueFlexibleAssetTypes 30 | $output.data 31 | ``` 32 | 33 | Your screen should look like this: 34 | 35 | ![](docs/DHCP_instructions_0.png) 36 | 37 | Find the `id` that corresponds to the DHCP flex asset type. Now that we have found it, fill it out in your config file. 38 | 39 | Next, let's find out what to put for the `key_name_` variables by running the following code to see what fields are attributed to the DHCP flex asset type: 40 | 41 | ```posh 42 | $output = Get-ITGlueFlexibleAssetFields -flexible_asset_type_id #insert your flex asset type id 43 | $output.data.attributes 44 | ``` 45 | 46 | ![](docs/DHCP_instructions_1.png) 47 | 48 | Each field should now be listed. In specific, the attribute we are looking for is called `name-key`. The data in this field is what we need to fill out our config file. For each element in the config file, fill out the corresponding `name-key` of the field returned by the aforementioned PowerShell commands. 49 | 50 | To make it a bit easier, feel free to list all of the `name-key` values in one shot, just be careful to get the correct ones: 51 | 52 | ```posh 53 | $output.data.attributes.'name-key' 54 | ``` 55 | 56 | ![](docs/DHCP_instructions_2.png) 57 | 58 | For our example shown in the screenshots, the following is what we would expect our `key_name_` elements to look like in our config file: 59 | 60 | ```posh 61 | @{ 62 | org_id = '' 63 | flexible_asset_type_id = 'xxxxx' 64 | 65 | key_name_ScopeName = 'scope-name' 66 | key_name_Server = 'server' 67 | key_name_ScopeBounds = 'scope-bounds' 68 | } 69 | ``` 70 | 71 | Once you are done, save your configuration file in the same directory as your script and make sure to pass the name of the file into the script using the `-api ` parameter if you want your script to automatically send data to IT Glue. 72 | 73 | ## Running the script for the first time 74 | 75 | After following the setup instructions, it is time to run your script. There are a few things to note: 76 | 77 | :warning: This script assumes that the servers it tags are in IT Glue as Configurations and that there is an exact name match. For example, if a file server is named "DC1", this script expects to have a configuration item in IT Glue under the current organization that has a name of "DC1". If this is not the case, the script will fail to appropriately create or update the flex asset. 78 | 79 | Once your configuration file is appropriately set up, all you need to do is run the script with `.\DHCP.ps1 -api api_config-DHCP.psd1` and the script will take care of the rest, including auto-updating the config document with the flexible asset id that is created. 80 | 81 | NOTE: Every organization in IT Glue has a specific id attached to it. If you are unaware of the id for the organization or client you are getting AD information for, you are welcome to use the scripts `-organization ` parameter. For example, if I am running this script at a client who's name in IT Glue is `Happy Frog`, I can run the script with `.\DHCP.ps1 -api api_config-DHCP.psd1 -organization "Happy Frog"`, and the script will automatically find the organization id. Do note that it looks for an **exact** match for the organization name. 82 | 83 | ---- 84 | 85 | Documentation :heart: Automation! -------------------------------------------------------------------------------- /File Shares/README.md: -------------------------------------------------------------------------------- 1 | # File Share Documentation Automation 2 | 3 | Getting accurate information for active file shares is crucial to properly support your clients. Let's look at a script that can automate the discovery of your file shares and create a Flex Asset in IT Glue to store the share information. 4 | 5 | ## Setup Instructions 6 | 7 | :warning: If you intend to use this script's API functionality, make sure you have installed the [IT Glue PowerShell Module](https://github.com/itglue/powershellwrapper) 8 | 9 | :warning: Make sure your File Share flexible asset type in IT Glue has fields corresponding to the ones outlined in `FileShares.flexasset`, as that is the data that this script is capable of finding. 10 | 11 | This script makes use of a configuration file to hold neccessary data that the API needs to be able to create and modify flexible assets. In the simplest form, that configuration file looks like: 12 | 13 | ```posh 14 | @{ 15 | org_id = '' 16 | flexible_asset_type_id = '' 17 | 18 | key_name_ShareName = '' 19 | key_name_ShareDescription = '' 20 | key_name_Server = '' 21 | key_name_SharePath = '' 22 | key_name_DiskPath = '' 23 | key_name_Permissions = '' 24 | } 25 | ``` 26 | 27 | The `flexible_asset_type_id` and all `key_name_` variables have to be filled out, however this is a one-time process, as these values are the same across your entire IT Glue account (and all organizations under it). To start with, let's find out the `flexible_asset_type_id` by running the following code: 28 | 29 | ```posh 30 | Import-Module ITGlueAPI 31 | 32 | $output = Get-ITGlueFlexibleAssetTypes 33 | $output.data 34 | ``` 35 | 36 | Your screen should look like this: 37 | 38 | ![](docs/FileShares_instructions_0.png) 39 | 40 | Find the `id` that corresponds to the File Share flex asset type. Now that we have found it, fill it out in your config file. 41 | 42 | Next, let's find out what to put for the `key_name_` variables by running the following code to see what fields are attributed to the File Share flex asset type: 43 | 44 | ```posh 45 | $output = Get-ITGlueFlexibleAssetFields -flexible_asset_type_id #insert your flex asset type id 46 | $output.data.attributes 47 | ``` 48 | 49 | ![](docs/FileShares_instructions_1.png) 50 | 51 | Each field should now be listed. In specific, the attribute we are looking for is called `name-key`. The data in this field is what we need to fill out our config file. For each element in the config file, fill out the corresponding `name-key` of the field returned by the aforementioned PowerShell commands. 52 | 53 | To make it a bit easier, feel free to list all of the `name-key` values in one shot, just be careful to get the correct ones: 54 | 55 | ```posh 56 | $output.data.attributes.'name-key' 57 | ``` 58 | 59 | ![](docs/FileShares_instructions_2.png) 60 | 61 | For our example shown in the screenshots, the following is what we would expect our `key_name_` elements to look like in our config file: 62 | 63 | ```posh 64 | @{ 65 | org_id = '' 66 | flexible_asset_type_id = 'xxxxx' 67 | 68 | key_name_ShareName = 'share-name' 69 | key_name_ShareDescription = 'share-description' 70 | key_name_Server = 'server' 71 | key_name_SharePath = 'share-path' 72 | key_name_DiskPath = 'disk-path' 73 | key_name_Permissions = 'permissions' 74 | } 75 | ``` 76 | 77 | Once you are done, save your configuration file in the same directory as your script and make sure to pass the name of the file into the script using the `-api ` parameter if you want your script to automatically send data to IT Glue. 78 | 79 | ## Running the script for the first time 80 | 81 | After following the setup instructions, it is time to run your script. There are a few things to note: 82 | 83 | :warning: This script assumes that the servers it tags are in IT Glue as Configurations and that there is an exact name match. For example, if a file server is named "FS1", this script expects to have a configuration item in IT Glue under the current organization that has a name of "FS1". If this is not the case, the script will fail to appropriately create or update the flex asset. 84 | 85 | Once your configuration file is appropriately set up, all you need to do is run the script with `.\FIleShares.ps1 -api api_config-FileShares.psd1` and the script will take care of the rest, including auto-updating the config document with the flexible asset id that is created. 86 | 87 | NOTE: Every organization in IT Glue has a specific id attached to it. If you are unaware of the id for the organization or client you are getting AD information for, you are welcome to use the scripts `-organization ` parameter. For example, if I am running this script at a client who's name in IT Glue is `Happy Frog`, I can run the script with `.\FileShares.ps1 -api api_config-FileShares.psd1 -organization "Happy Frog"`, and the script will automatically find the organization id. Do note that it looks for an **exact** match for the organization name. 88 | 89 | ---- 90 | 91 | Documentation :heart: Automation! -------------------------------------------------------------------------------- /Cloudflare/CloudflareITGlue/Public/New-CloudflareITGlueFlexAssetType.ps1: -------------------------------------------------------------------------------- 1 | function New-CloudflareITGlueFlexAssetType { 2 | param( 3 | [string]$Name = 'Cloudflare DNS' 4 | ) 5 | 6 | $Body = @{ 7 | Data = @{ 8 | type = 'flexible_asset_types' 9 | attributes = @{ 10 | name = $Name 11 | description = 'DNS Zones from Cloudflare.' 12 | icon = 'cloud' 13 | enabled = $true 14 | show_in_menu = $false 15 | } 16 | 17 | relationships = @{ 18 | flexible_asset_fields = @{ 19 | data = @( 20 | @{ 21 | type = 'flexible_asset_fields' 22 | attributes = @{ 23 | order = 1 24 | name = 'Name' 25 | kind = 'Text' 26 | hint = 'Name of the DNS Zone' 27 | required = $true 28 | show_in_list = $true 29 | use_for_title = $true 30 | } 31 | }, 32 | @{ 33 | type = 'flexible_asset_fields' 34 | attributes = @{ 35 | order = 2 36 | name = 'Last Sync' 37 | kind = 'Text' 38 | hint = 'When zone last synced (UTC)' 39 | required = $true 40 | show_in_list = $false 41 | } 42 | }, 43 | @{ 44 | type = 'flexible_asset_fields' 45 | attributes = @{ 46 | order = 3 47 | name = 'Nameservers' 48 | kind = 'Textbox' 49 | hint = 'Cloudflare provided nameservers for this zone' 50 | required = $true 51 | show_in_list = $false 52 | } 53 | }, 54 | @{ 55 | type = 'flexible_asset_fields' 56 | attributes = @{ 57 | order = 4 58 | name = 'Status' 59 | kind = 'Text' 60 | hint = 'Status of the Cloudflare Zone' 61 | required = $false 62 | show_in_list = $true 63 | } 64 | }, 65 | @{ 66 | type = 'flexible_asset_fields' 67 | attributes = @{ 68 | order = 5 69 | name = 'Zone File' 70 | kind = 'Upload' 71 | hint = 'Exported zone file in BIND format. You can upload this to Cloudflare. UTF-8 Encoded, use notepad++ for better viewing.' 72 | required = $false 73 | show_in_list = $false 74 | } 75 | }, 76 | @{ 77 | type = 'flexible_asset_fields' 78 | attributes = @{ 79 | order = 6 80 | name = 'Domain Tracker' 81 | kind = 'Tag' 82 | hint = 'Tagged in Domain Tracker' 83 | tag_type = 'Domains' 84 | required = $false 85 | show_in_list = $false 86 | } 87 | }, 88 | @{ 89 | type = 'flexible_asset_fields' 90 | attributes = @{ 91 | order = 7 92 | name = 'DNS Records' 93 | kind = 'Textbox' 94 | hint = 'Table of DNS records in the zone' 95 | required = $true 96 | show_in_list = $false 97 | } 98 | } 99 | ) 100 | } 101 | } 102 | } 103 | } 104 | $Body = $Body | ConvertTo-Json -Depth 6 105 | New-ITGlueWebRequest -Endpoint 'flexible_asset_types' -Method 'POST' -Body $Body 106 | } -------------------------------------------------------------------------------- /Cloudflare/CloudflareITGlue/CloudflareITGlue.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'CloudflareITGlue' 3 | # 4 | # Generated by: Jeremy Colby 5 | # 6 | # Generated on: 10/30/2018 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'CloudflareITGlue.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.1.0' 16 | 17 | # Supported PSEditions 18 | # CompatiblePSEditions = @() 19 | 20 | # ID used to uniquely identify this module 21 | GUID = '55a62423-f6e4-4548-ba2a-7387a32ff6d3' 22 | 23 | # Author of this module 24 | Author = 'Jeremy Colby' 25 | 26 | # Company or vendor of this module 27 | CompanyName = '' 28 | 29 | # Copyright statement for this module 30 | Copyright = '(c) 2018 Jeremy Colby. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | # Description = '' 34 | 35 | # Minimum version of the Windows PowerShell engine required by this module 36 | PowerShellVersion = '5.0' #New-TemporaryFile seems like only incompatiblity with 4.0 37 | 38 | # Name of the Windows PowerShell host required by this module 39 | # PowerShellHostName = '' 40 | 41 | # Minimum version of the Windows PowerShell host required by this module 42 | # PowerShellHostVersion = '' 43 | 44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 45 | # DotNetFrameworkVersion = '' 46 | 47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 48 | # CLRVersion = '' 49 | 50 | # Processor architecture (None, X86, Amd64) required by this module 51 | # ProcessorArchitecture = '' 52 | 53 | # Modules that must be imported into the global environment prior to importing this module 54 | # RequiredModules = @() 55 | 56 | # Assemblies that must be loaded prior to importing this module 57 | # RequiredAssemblies = @() 58 | 59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 60 | # ScriptsToProcess = @() 61 | 62 | # Type files (.ps1xml) to be loaded when importing this module 63 | # TypesToProcess = @() 64 | 65 | # Format files (.ps1xml) to be loaded when importing this module 66 | # FormatsToProcess = @() 67 | 68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 69 | NestedModules = 'Private\CloudflareWebRequest.ps1', 70 | 'Private\CloudflareZoneData.ps1', 71 | 'Private\ITGlueWebRequest.ps1', 72 | 'Public\CloudflareITGlueAPIAuth.ps1', 73 | 'Public\New-CloudflareITGlueFlexAssetType.ps1', 74 | 'Public\Sync-CloudflareITGlueFlexibleAssets.ps1' 75 | 76 | 77 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 78 | FunctionsToExport = 'Add-CloudflareITGlueAPIAuth', 79 | 'Get-CloudflareITGlueAPIAuth', 80 | 'Remove-CloudflareITGlueAPIAuth', 81 | 'New-CloudflareITGlueFlexAssetType', 82 | 'Sync-CloudflareITGlueFlexibleAssets' 83 | 84 | 85 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 86 | CmdletsToExport = @() 87 | 88 | # Variables to export from this module 89 | VariablesToExport = @() 90 | 91 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 92 | AliasesToExport = @() 93 | 94 | # DSC resources to export from this module 95 | # DscResourcesToExport = @() 96 | 97 | # List of all modules packaged with this module 98 | # ModuleList = @() 99 | 100 | # List of all files packaged with this module 101 | # FileList = @() 102 | 103 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 104 | PrivateData = @{ 105 | 106 | PSData = @{ 107 | 108 | # Tags applied to this module. These help with module discovery in online galleries. 109 | # Tags = @() 110 | 111 | # A URL to the license for this module. 112 | # LicenseUri = '' 113 | 114 | # A URL to the main website for this project. 115 | # ProjectUri = '' 116 | 117 | # A URL to an icon representing this module. 118 | # IconUri = '' 119 | 120 | # ReleaseNotes of this module 121 | # ReleaseNotes = '' 122 | 123 | } # End of PSData hashtable 124 | 125 | } # End of PrivateData hashtable 126 | 127 | # HelpInfo URI of this module 128 | # HelpInfoURI = '' 129 | 130 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 131 | # DefaultCommandPrefix = '' 132 | 133 | } 134 | 135 | -------------------------------------------------------------------------------- /Cloudflare/CloudflareITGlue/Private/CloudflareZoneData.ps1: -------------------------------------------------------------------------------- 1 | function Get-CloudflareZoneData { 2 | param( 3 | [Parameter(Mandatory = $true)][string]$ZoneId, 4 | [Parameter(Mandatory = $true)][pscustomobject]$ITGMatch 5 | ) 6 | 7 | $Timestamp = (Get-Date).ToUniversalTime().ToString("yyyy-M-d HH:mm:ss") 8 | $AccountId = New-CloudflareWebRequest -Endpoint 'accounts' | ForEach-Object result | ForEach-Object id 9 | $ZoneInfo = New-CloudflareWebRequest -Endpoint "zones/$ZoneId" 10 | $ZoneRecords = New-CloudflareWebRequest -Endpoint "zones/$ZoneId/dns_records" 11 | if ($ZoneRecords.result_info.count -eq 0) { 12 | Write-Host "$($ZoneInfo.result.name): Empty Zone Detected" -ForegroundColor Yellow 13 | break 14 | } 15 | $ZoneFileData = New-CloudflareWebRequest -Endpoint "zones/$ZoneId/dns_records/export" 16 | $ZoneFileData = $ZoneFileData.Replace( 17 | "@ 3600 IN SOA $($ZoneInfo.result.name). root.$($ZoneInfo.result.name). (", 18 | "@ 3600 IN SOA $($ZoneInfo.result.name_servers[0]). $((($CloudflareAPIEmail -split '@')[0]).Replace('.','\.') + '.'+ ($CloudflareAPIEmail -split '@')[1]). (" 19 | ) 20 | $ZoneFileData = $ZoneFileData.Replace( 21 | ";; NS Records (YOU MUST CHANGE THIS)`n$($ZoneInfo.result.name). 1 IN NS " + 'REPLACE&ME$WITH^YOUR@NAMESERVER.', 22 | ";; NS Records`n$($ZoneInfo.result.name). 1 IN NS $($ZoneInfo.result.name_servers[0]).`n$($ZoneInfo.result.name). 1 IN NS $($ZoneInfo.result.name_servers[1])." 23 | ) 24 | $ZoneFileData = $ZoneFileData.Replace( 25 | ';; -- update the SOA record with the correct authoritative name server', 26 | ";; -- update the SOA record with the correct authoritative name server`n;; ** CloudflareITGlue Module: Updated $($Timestamp)" 27 | ) 28 | $ZoneFileData = $ZoneFileData.Replace( 29 | ';; -- update the SOA record with the contact e-mail address information', 30 | ";; -- update the SOA record with the contact e-mail address information`n;; ** CloudflareITGlue Module: Updated $($Timestamp)" 31 | ) 32 | $ZoneFileData = $ZoneFileData.Replace( 33 | ';; -- update the NS record(s) with the authoritative name servers for this domain.', 34 | ";; -- update the NS record(s) with the authoritative name servers for this domain.`n;; ** CloudflareITGlue Module: Updated $($Timestamp)" 35 | ) 36 | $RecordsHtml = 37 | '
38 |

39 | 40 | Open in Cloudflare 41 |

42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | ' + 53 | $(foreach ($Record in $ZoneRecords.result) { 54 | " 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | " 63 | }) + 64 | ' 65 |
TypeNameValuePriorityTTLProxiedModified
$($Record.type)$($Record.name)$($Record.content)$($Record.priority)$(if ($Record.ttl -eq 1){'Auto'}else{$Record.ttl})$($Record.proxied)$(($Record.modified_on.Replace('T', ' ') -split '\.')[0])
66 |
' 67 | 68 | $ZoneData = [ordered]@{ 69 | Name = $ZoneInfo.result.name 70 | SyncDate = $Timestamp 71 | CfNameServers = $ZoneInfo.result.name_servers 72 | Status = $ZoneInfo.result.status 73 | ZoneFileData = $ZoneFileData 74 | RecordsHtml = $RecordsHtml 75 | ITGOrg = $Match.OrgMatchId 76 | DomainTracker = $Match.DomainTrackerId 77 | } 78 | $ZoneData 79 | } 80 | 81 | function Get-CloudflareZoneDataArray { 82 | $ZoneDataArray = @() 83 | $AllZones = New-CloudflareWebRequest -Endpoint 'zones' 84 | [pscustomobject]$ITGDomains = New-ITGlueWebRequest -Endpoint 'domains' | ForEach-Object data 85 | $Progress = 0 86 | 87 | foreach ($Zone in $AllZones.result) { 88 | Write-Progress -Activity 'CloudflareAPI' -Status 'Getting Zone Data' -CurrentOperation $Zone.name -PercentComplete ($Progress / ($AllZones.result | Measure-Object | ForEach-Object count) * 100) -Id 1 89 | 90 | $ITGMatches = @() 91 | foreach ($ITGDomain in $ITGDomains) { 92 | if ($Zone.name.ToLower() -eq $ITGDomain.attributes.name.ToLower()) { 93 | $Match = @{ 94 | OrgMatchId = $ITGDomain.attributes.'organization-id' 95 | DomainTrackerId = $ITGDomain.id 96 | } 97 | $ITGMatches += [pscustomobject]$Match 98 | } 99 | } 100 | if($ITGMatches){ 101 | foreach ($Match in $ITGMatches) { 102 | $ZoneData = Get-CloudflareZoneData -ZoneId $Zone.id -ITGMatch $Match 103 | if ($ZoneData) { 104 | $ZoneDataArray += [pscustomobject]$ZoneData 105 | } 106 | } 107 | } 108 | else{ 109 | Write-Host "$($Zone.name): Add to domain tracker" -ForegroundColor Yellow 110 | } 111 | $Progress++ 112 | } 113 | Write-Progress -Activity 'CloudflareAPI' -Status 'Complete' -PercentComplete 100 -Id 1 114 | $ZoneDataArray 115 | } 116 | -------------------------------------------------------------------------------- /Python Tooling Scripts/copy_flexible_asset_types.py: -------------------------------------------------------------------------------- 1 | import itglue 2 | import json 3 | import os 4 | import re 5 | 6 | DIR_PATH = os.path.dirname(os.path.realpath(__file__)) 7 | EXCLUDE_KEYS = ['flexible_asset_type_id', 'created_at', 'updated_at', 'id'] 8 | 9 | 10 | class ITGlueError(Exception): 11 | pass 12 | 13 | 14 | def copy_flex_types(target_api, flex_types): 15 | """Create flexible asset types that does not have a 16 | flexible asset type tag field in the new account 17 | Returns 3 lists: 18 | * Created types in the new account with its corresponding new ID 19 | * List of flexible asset fields with tag-type of another flexible asset types 20 | * List of flexible asset types with only tag-types of "FlexibleAssetType" 21 | """ 22 | fa_types_matching = {} 23 | tag_fields = [] 24 | all_fields = get_all_fields(flex_types) 25 | set_connection_creds(target_api) 26 | tags_only_types = [] 27 | for flex_type in flex_types: 28 | flex_asset_type = find_or_initialize_flex_type(flex_type.attributes['name']) 29 | flex_id = flex_type.id 30 | if not flex_asset_type.id: 31 | tagged_fields, new_fields = extract_tag_type(flex_id, all_fields[flex_id]) 32 | flex_type_attr = extract_attributes(flex_type.attributes) 33 | updated_flex_type = itglue.FlexibleAssetType(**flex_type_attr) 34 | if new_fields: 35 | created_type = create_new_flex_types(updated_flex_type, new_fields) 36 | fa_types_matching[flex_id] = created_type.id 37 | tag_fields.extend(tagged_fields) 38 | else: 39 | tag_type = {'id': flex_id, 40 | 'type': updated_flex_type, 41 | 'fields': all_fields[flex_id]} 42 | tags_only_types.append(tag_type) 43 | else: 44 | fa_types_matching[flex_id] = flex_asset_type.id 45 | return fa_types_matching, tag_fields, tags_only_types 46 | 47 | 48 | def create_field_tag_type(fields, new_type_ids): 49 | """Create new FlexibleAssetField with the new flex type ID""" 50 | for field in fields: 51 | for key, value in field.items(): 52 | new_field = update_tag_type_id(value, new_type_ids) 53 | if new_field and (key in new_type_ids.keys()): 54 | new_field.attributes['flexible_asset_type_id'] = new_type_ids[key] 55 | new_field.create() 56 | else: 57 | print('Unable to create tag field for:\n\tsource flexible asset type ID: {}\n\ttarget flexible asset type ID: {}'.format(key, new_type_ids[key])) 58 | 59 | 60 | def create_tags_only_types(flex_types, new_type_ids): 61 | """Copy types that only has FlexibleAssetType tag fields""" 62 | while flex_types: 63 | flex_type = flex_types.pop() 64 | updated_fields = [] 65 | for field in flex_type['fields']: 66 | new_field = update_tag_type_id(field, new_type_ids) 67 | if new_field: 68 | updated_fields.append(new_field) 69 | else: 70 | flex_types.append(flex_type) 71 | if updated_fields: 72 | created_type = create_new_flex_types(flex_type['type'], updated_fields) 73 | new_type_ids[flex_type['id']] = created_type.id 74 | 75 | 76 | def extract_tag_type(type_id, fields): 77 | """Remove all fields that have a FlexibleAssetType tag-type""" 78 | tagged_fields = [] 79 | fields_copy = fields[:] 80 | for index, field in enumerate(fields_copy[:]): 81 | attr = field.attributes 82 | if attr['kind'] == 'Tag' and ('FlexibleAssetType:' in attr['tag_type']): 83 | tagged_fields.append({type_id: field}) 84 | fields_copy.remove(field) 85 | return tagged_fields, fields_copy 86 | 87 | 88 | def update_tag_type_id(field, new_type_ids): 89 | """Update tag field with the new flexible asset type ID in target account""" 90 | tag_id = extract_field_id(field) 91 | try: 92 | field.attributes['tag_type'] = 'FlexibleAssetType: {}'.format(new_type_ids[tag_id]) 93 | return field 94 | except KeyError: 95 | return False 96 | 97 | 98 | def find_or_initialize_flex_type(type_name): 99 | """ 100 | Returns type with the same name in the target account or initialize 101 | a new flexible asset type 102 | """ 103 | flex_type = itglue.FlexibleAssetType.first_or_initialize(name=type_name) 104 | if flex_type.id: 105 | print('{} already exists'.format(type_name)) 106 | return flex_type 107 | 108 | 109 | def create_new_flex_types(new_type, new_fields): 110 | flex_name = new_type.attributes['name'] 111 | created_type = new_type.create(flexible_asset_fields=new_fields) 112 | print('{} copied'.format(flex_name)) 113 | return created_type 114 | 115 | 116 | def set_connection_creds(api_key): 117 | itglue.connection.api_key = api_key 118 | 119 | 120 | def get_api_url_and_key(): 121 | with open('{}/params.json'.format(DIR_PATH)) as file: 122 | params = json.load(file) 123 | itglue.connection.api_url = params['APIUrl'] 124 | return params['SourceAccountAPIKey'], params['TargetAccountAPIKEy'] 125 | 126 | 127 | def get_all_flex_types(api_key): 128 | """Get all flexible asset types from source account""" 129 | set_connection_creds(api_key) 130 | flex_types = itglue.FlexibleAssetType.get() 131 | return flex_types 132 | 133 | 134 | def extract_field_id(field): 135 | tag_id = re.search('(?<=FlexibleAssetType: )\d+', field.attributes['tag_type']) 136 | return tag_id.group(0) 137 | 138 | 139 | def get_all_fields(flex_types): 140 | all_fields = {} 141 | for flex_type in flex_types: 142 | fields = get_flex_asset_fields(flex_type) 143 | all_fields[flex_type.id] = fields 144 | return all_fields 145 | 146 | 147 | def get_flex_asset_fields(flex_type): 148 | """Create new flexible asset fields with original attributes""" 149 | updated_fields = [] 150 | flex_asset_fields = itglue.FlexibleAssetField.get(parent=flex_type) 151 | if not flex_asset_fields: 152 | return ITGlueError('This flexible asset type {} does not have any fields.'.format(flex_type.attributes['name'])) 153 | for field in flex_asset_fields: 154 | field_attr = extract_attributes(field.attributes) 155 | flex_field = itglue.FlexibleAssetField(**field_attr) 156 | updated_fields.append(flex_field) 157 | return updated_fields 158 | 159 | 160 | def extract_attributes(attributes): 161 | for key in EXCLUDE_KEYS: 162 | attributes.pop(key, None) 163 | return attributes 164 | 165 | 166 | def main(): 167 | source_api, target_api = get_api_url_and_key() 168 | flex_types = get_all_flex_types(source_api) 169 | type_id_mapping, tagged_list, tags_only_types = copy_flex_types(target_api, flex_types) 170 | create_field_tag_type(tagged_list, type_id_mapping) 171 | create_tags_only_types(tags_only_types, type_id_mapping) 172 | 173 | 174 | if __name__ == '__main__': 175 | main() 176 | -------------------------------------------------------------------------------- /DHCP/DHCP.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | 3 | .SYNOPSIS 4 | This script grabs all DHCP servers in a domain and provides their name, status, and scope 5 | 6 | .DESCRIPTION 7 | Options: 8 | 9 | -help - Display the current help menu 10 | -silent - Run the script without printing anything 11 | -file - Declare a location to save script output to as a csv 12 | -organization - Declare the name of the organization 13 | 14 | 15 | .EXAMPLE 16 | ./DHCP.ps1 -s -c -url api.example.com 17 | ./DHCP.ps1 -FQDN -file C:\adout.csv 18 | 19 | .NOTES 20 | Author: Mark Jacobs 21 | Author: Caleb Albers 22 | 23 | .LINK 24 | https://github.com/itglue/automation 25 | 26 | #> 27 | 28 | 29 | Param ( 30 | [switch]$help = $False, 31 | [switch]$silent = $False, 32 | [switch]$continuum = $False, 33 | [string]$url, 34 | [string]$file, 35 | [string]$organization = "" 36 | ) 37 | 38 | # Print Results 39 | function writeOutput { 40 | Write-Host "Organization Name: `t" -ForegroundColor Gray -NoNewline 41 | Write-Host "`t `t" $organization "`n" 42 | 43 | Write-Host "DHCP Scope Name: `t" -ForegroundColor Gray -NoNewline 44 | Write-Host "`t `t" $Name "`n" 45 | 46 | Write-Host "Getting Server Name: `t" -ForegroundColor Gray -NoNewline 47 | Write-Host "`t `t" $Server "`n" 48 | 49 | Write-Host "Status: `t" -ForegroundColor Gray -NoNewline 50 | Write-Host "`t `t" $organization "`n" 51 | 52 | Write-Host "Scope: `t" -ForegroundColor Gray -NoNewline 53 | Write-Host "`t `t" $Start " - " $End "`n" 54 | } 55 | function updateAPIConfigFile { 56 | 57 | $api__flex_asset_type_id = $api_config.flexible_asset_type_id 58 | 59 | $api__key_name_ScopeName = $api_config.key_name_ScopeName 60 | $api__key_name_Server = $api_config.key_name_Server 61 | $api__key_name_ScopeBounds = $api_config.key_name_ScopeBounds 62 | 63 | 64 | @" 65 | @{ 66 | org_id = '$api__org_id' 67 | flexible_asset_type_id = '$api__flex_asset_type_id' 68 | 69 | key_name_ScopeName = '$api__key_name_ScopeName' 70 | key_name_Server = '$api__key_name_Server' 71 | key_name_ScopeBounds = '$api__key_name_ScopeBounds' 72 | } 73 | "@ | Out-File -FilePath $api -Force 74 | } 75 | 76 | function formatAPIData { 77 | 78 | $api__flex_asset_type_id = $api_config.flexible_asset_type_id 79 | 80 | $api__key_name_ScopeName = $api_config.key_name_ScopeName 81 | $api__key_name_Server = $api_config.key_name_Server 82 | $api__key_name_ScopeBounds = $api_config.key_name_ScopeBounds 83 | 84 | 85 | if($api_config.org_id) { 86 | $api__org_id = $api_config.org_id 87 | } 88 | elseif($organization) { 89 | 90 | Write-Host "No organization id was specified in the config file, attempting an ` 91 | auto-match based on the name: " $organization -ForegroundColor Yellow 92 | 93 | $attempted_match = Get-ITGlueOrganizations -filter_name "$organization" 94 | 95 | if($attempted_match.data[0].attributes.name -eq $organization) { 96 | Write-Host "Auto-match successful. Updating config file with organization id." -ForegroundColor Green 97 | 98 | $api__org_id = $attempted_match.data.id 99 | 100 | updateAPIConfigFile 101 | 102 | } 103 | else { 104 | Write-Error "No auto-match was found. Please pass the exact name to -organization or ` 105 | add the organization id to the config file." 106 | 107 | return 108 | } 109 | } 110 | else { 111 | Write-Error "No organization id was found. Please add an organization id to the config file ` 112 | or attempt a match by putting the full name in the -organization parameter." 113 | 114 | return 115 | } 116 | 117 | $api__Server_id = (Get-ITGlueConfigurations -filter_organization_id $api__org_id -filter_name $currentServer)[0].id 118 | 119 | $api__body = @{ 120 | type = "flexible_assets" 121 | attributes = @{ 122 | organization_id = $api__org_id 123 | flexible_asset_type_id = $api_config.flexible_asset_type_id 124 | traits = @{ 125 | $api__key_name_ScopeName = $share 126 | $api__key_name_Server = $api__Server_id 127 | $api__key_name_ScopeBounds = $Start + " - " + $End 128 | } 129 | } 130 | } 131 | 132 | return $api__body 133 | } 134 | 135 | if($help) { 136 | Get-Help $MyInvocation.MyCommand.Path 137 | exit 138 | } 139 | 140 | if(($silent) -and !($url -or $file -or $ftp)) { 141 | Write-Error -Message "ERROR: Using the silent flag requires a URL, FTP server, or location to save results to." ` 142 | -Category InvalidOperation ` 143 | } 144 | else { 145 | if($continuum) { 146 | $organization = (Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\SAAZOD").SITENAME 147 | } 148 | 149 | # Get DHCP v4 Scopes 150 | $DHCPs = Get-DhcpServerv4Scope 151 | $Server = [System.Net.Dns]::GetHostName() 152 | 153 | ForEach($DHCP in $DHCPs){ 154 | $Start = $DHCP.StartRange 155 | $End = $DHCP.EndRange 156 | $Status = $DHCP.State 157 | $Name = $DHCP.Name 158 | 159 | if(!$silent){writeOutput} 160 | 161 | if($file -or $ftp) { 162 | $PostData = @{ 163 | Organization = $organization; ` 164 | Name = $Name; ` 165 | Status = $Status; ` 166 | Scope = "$Start - $End"; ` 167 | Server = $Server; 168 | } 169 | } 170 | if($file) { 171 | $SaveData += New-Object PSObject -Property $PostData 172 | } 173 | if($api) { 174 | try { 175 | Import-Module ITGlueAPI 176 | } 177 | catch { 178 | Write-Error "ERROR: The IT Glue API PowerShell module cannot be imported." 179 | Write-Error "Please download it from https://github.com/itglue/powershellwrapper, configure it, and try again." 180 | } 181 | 182 | if(test-path $api) { 183 | $api_config = Import-LocalizedData -FileName "$api" 184 | 185 | Write-Host "DHCP flex asset configuration file found!" -ForegroundColor Green 186 | 187 | $api__body = formatAPIData # format data for API call 188 | $api__org_id = $api__body.data.attributes.organization_id 189 | $api__flex_asset_id = $api_config.flex_asset_id 190 | 191 | if($api__org_id) { 192 | Write-Host "Creating a new flexible asset." 193 | 194 | ConvertTo-Json $api__body -Depth 100 195 | 196 | $api__output_data = New-ITGlueFlexibleAssets -data $api__body 197 | 198 | $api__output_data 199 | } 200 | } 201 | else { 202 | Write-Error "ERROR: DHCP flex asset configuration file was found. Please create one and re-run the script." 203 | } 204 | } 205 | } 206 | if($file) { 207 | $SaveData | export-csv -Path $file -NoTypeInformation 208 | } 209 | } -------------------------------------------------------------------------------- /Active Directory/Initialize-ActiveDirectoryFlexAsset.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | 3 | Initialize-ActiveDirectoryFlexAsset.ps1 4 | 5 | This script creates a new flexible asset type in IT Glue with all the fields neccessary for the Active Directory script to run. 6 | It also generates a configuration file that can be used to run the Active Directory data collection script. 7 | 8 | Keep in mind that the configuration file generated still needs to have an organization id manually added. 9 | 10 | This script creates the Flexible Asset Type with the name "Active Directory". If an existing Flexible Asset Type with that 11 | name is present, it will ask you if you wish to rename the existing record. If so, it will be renamed "Active Directory (OLD)". 12 | No data will be lost in this -- the flexible asset type will simply be renamed. If you select NO, a flexible asset type with 13 | the name "Active Directory [AUTO]" will be created. You may rename this in the IT Glue Admin Panel at any time. 14 | 15 | #> 16 | 17 | 18 | 19 | try { 20 | Import-Module ITGlueAPI 21 | } 22 | catch { 23 | Write-Error "Failed to import the ITGlueAPI module. Is it installed?" 24 | Exit 25 | } 26 | 27 | # Check if a flex asset with the name "Active Directory" already exists 28 | $existing_FATs = Get-ITGlueFlexibleAssetTypes 29 | $ad_fat_name = "Active Directory" 30 | 31 | $existing_ad_fat = $existing_FATs.data | Where-Object {$_.attributes.name -eq "Active Directory"} 32 | 33 | if($existing_ad_fat) { 34 | Write-Host 'A flexible asset type with the name "Active Directory" already exists. Would you like to rename the existing flexible asset type to "Active Directory (OLD)"? This is an optional operation, and no data will be lost.' 35 | 36 | $yes = New-Object Management.Automation.Host.ChoiceDescription '&Yes' 37 | $no = New-Object Management.Automation.Host.ChoiceDescription '&No' 38 | $options = [Management.Automation.Host.ChoiceDescription[]]($yes, $no) 39 | $default = 1 # $no 40 | 41 | $answer = $Host.UI.PromptForChoice($title, $msg, $options, $default) 42 | 43 | if($answer) { 44 | Write-Host 'No was selected. A new flexible asset type with the name "Active Directory [AUTO]" will be created. You can rename it at any time from the IT Glue Admin panel.' 45 | $ad_fat_name = "Active Directory [AUTO]" 46 | } 47 | else { 48 | $renamed_AD = @{ 49 | type = 'flexible_asset_types' 50 | attributes = @{ 51 | name = 'Active Directory (OLD)' 52 | } 53 | } 54 | try { 55 | $output = Set-ITGlueFlexibleAssetTypes -data $renamed_AD -id $existing_ad_fat.id 56 | } 57 | catch { 58 | Throw "Flexible Asset Type rename failed. Please change the name in the IT Glue Admin panel, or try again." 59 | } 60 | } 61 | } 62 | 63 | 64 | $data = @{ 65 | type = 'flexible_asset_types' 66 | attributes = @{ 67 | name = $ad_fat_name 68 | description = '' 69 | icon = 'windows' 70 | show_in_menu = $true 71 | enabled = $true 72 | } 73 | relationships = @{ 74 | flexible_asset_fields = @{ 75 | data = @( 76 | @{ 77 | type = 'flexible_asset_fields' 78 | attributes = @{ 79 | order = 1 80 | name = 'Forest Name' 81 | kind = 'Text' 82 | hint = 'Full forest name - e.g. domain.com' 83 | default_value = '' 84 | required = $true 85 | show_in_list = $true 86 | } 87 | }, 88 | @{ 89 | type = 'flexible_asset_fields' 90 | attributes = @{ 91 | order = 2 92 | name = 'Domain Full Name' 93 | kind = 'Text' 94 | hint = 'Full Active Directory domain name - e.g. corp.domain.com' 95 | default_value = '' 96 | required = $true 97 | show_in_list = $true 98 | use_for_title = $true 99 | } 100 | }, 101 | @{ 102 | type = 'flexible_asset_fields' 103 | attributes = @{ 104 | order = 3 105 | name = 'Domain Short Name' 106 | kind = 'Text' 107 | hint = 'Short Active Directory domain name - e.g. CORP' 108 | default_value = '' 109 | required = $true 110 | show_in_list = $true 111 | use_for_title = $true 112 | } 113 | }, 114 | @{ 115 | type = 'flexible_asset_fields' 116 | attributes = @{ 117 | order = 4 118 | name = 'AD Level' 119 | kind = 'Select' 120 | hint = 'Forest Functional Level' 121 | default_value = "2000`r`n" ` 122 | + "2003`r`n" ` 123 | + "2008`r`n" ` 124 | + "2008 R2`r`n" ` 125 | + "2012`r`n" ` 126 | + "2012 R2`r`n" ` 127 | + "2016`r`n" 128 | required = $true 129 | show_in_list = $false 130 | } 131 | }, 132 | @{ 133 | type = 'flexible_asset_fields' 134 | attributes = @{ 135 | order = 5 136 | name = 'Schema Master' 137 | kind = 'Tag' 138 | tag_type = 'Configurations' 139 | required = $false 140 | show_in_list = $false 141 | } 142 | }, 143 | @{ 144 | type = 'flexible_asset_fields' 145 | attributes = @{ 146 | order = 6 147 | name = 'Domain Naming Master' 148 | kind = 'Tag' 149 | tag_type = 'Configurations' 150 | required = $false 151 | show_in_list = $false 152 | } 153 | }, 154 | @{ 155 | type = 'flexible_asset_fields' 156 | attributes = @{ 157 | order = 7 158 | name = 'Relative ID (RID) Master' 159 | kind = 'Tag' 160 | tag_type = 'Configurations' 161 | required = $false 162 | show_in_list = $false 163 | } 164 | }, 165 | @{ 166 | type = 'flexible_asset_fields' 167 | attributes = @{ 168 | order = 8 169 | name = 'PDC Emulator Master' 170 | kind = 'Tag' 171 | tag_type = 'Configurations' 172 | required = $false 173 | show_in_list = $false 174 | } 175 | }, 176 | @{ 177 | type = 'flexible_asset_fields' 178 | attributes = @{ 179 | order = 9 180 | name = 'Infrastructure Master' 181 | kind = 'Tag' 182 | tag_type = 'Configurations' 183 | required = $false 184 | show_in_list = $false 185 | } 186 | }, 187 | @{ 188 | type = 'flexible_asset_fields' 189 | attributes = @{ 190 | order = 10 191 | name = 'Global Catalog Servers (Domain Controllers)' 192 | kind = 'Tag' 193 | tag_type = 'Configurations' 194 | required = $false 195 | show_in_list = $false 196 | } 197 | }, 198 | @{ 199 | type = 'flexible_asset_fields' 200 | attributes = @{ 201 | order = 11 202 | name = 'Notes' 203 | kind = 'Textbox' 204 | required = $false 205 | show_in_list = $false 206 | } 207 | } 208 | ) 209 | } 210 | } 211 | } 212 | 213 | 214 | try { 215 | $output = New-ITGlueFlexibleAssetTypes -data $data 216 | } 217 | catch { 218 | Throw "Unable to create Flexible Asset Type." 219 | } 220 | 221 | if($output) { 222 | Write-Host "Active Directory Flexible Asset Type successfully created." 223 | 224 | $fat_id = $output.data.id 225 | 226 | $configuration = @" 227 | @{ 228 | # REQUIRED 229 | org_id = '' 230 | 231 | # Auto-Generated 232 | flexible_asset_type_id = '$fat_id' 233 | 234 | key_name_ADForestName = 'forest-name' 235 | key_name_ADFunctionalLevel = 'ad-level' 236 | key_name_DomainName = 'domain-full-name' 237 | key_name_DomainShortName = 'domain-short-name' 238 | key_name_SchemaMaster = 'schema-master' 239 | key_name_DomainNamingMaster = 'domain-naming-master' 240 | key_name_RIDMaster = 'relative-id-rid-master' 241 | key_name_PDCEmulator = 'pdc-emulator-master' 242 | key_name_InfrastructureMaster = 'infrastructure-master' 243 | key_name_GlobalCatalogServers = 'global-catalog-servers-domain-controllers' 244 | 245 | } 246 | "@ 247 | 248 | try { 249 | $configuration | Out-File -FilePath ("config.psd1") -Force 250 | } 251 | catch { 252 | Write-Error "Configuration file failed to save. Printing the file for easy reference:" 253 | } 254 | 255 | Write-Host $configuration -ForegroundColor "Green" 256 | } -------------------------------------------------------------------------------- /File Shares/FileShares.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script grabs all shared folders in the current server along with their shared path, disk path and permsissions 4 | 5 | .DESCRIPTION 6 | Options: 7 | 8 | -help - Display the current help menu 9 | -silent - Run the script without printing anything 10 | -api - Declare a file name for an API config file to post flex asset directly to IT Glue 11 | -file - Declare a location to save script output to as a csv 12 | -organization - Declare the name of the organization 13 | 14 | .NOTES 15 | This script is largely a modification on grolo's "Audit File Share Perms" script available at http://poshcode.org/3398. 16 | We thank grolo for doing a lot of the heavy lifting for us. 17 | 18 | Author: Mark Jacobs 19 | Author: Caleb Albers 20 | 21 | .LINK 22 | https://github.com/itglue/automation 23 | 24 | #> 25 | 26 | [cmdletbinding()] 27 | 28 | Param ( 29 | [switch]$help = $False, 30 | [switch]$silent = $False, 31 | [switch]$continuum = $False, 32 | [string]$api, 33 | [string]$file, 34 | [string]$organization = "" 35 | ) 36 | 37 | # Print Results 38 | function writeOutput { 39 | Write-Host "Organization Name: `t" -ForegroundColor Gray -NoNewline 40 | Write-Host "`t `t" $organization "`n" 41 | 42 | Write-Host "Server: `t" -ForegroundColor Gray -NoNewline 43 | Write-Host "`t `t" $currentServer "`n" 44 | 45 | Write-Host "Share Name: `t" -ForegroundColor Gray -NoNewline 46 | Write-Host "`t `t" $share "`n" 47 | 48 | Write-Host "Share Path: `t" -ForegroundColor Gray -NoNewline 49 | Write-Host "`t `t" $writePath "`n" 50 | 51 | Write-Host "Share Description: `t" -ForegroundColor Gray -NoNewline 52 | Write-Host "`t `t" $ShareDescription "`n" 53 | 54 | Write-Host "Disk Path: `t" -ForegroundColor Gray -NoNewline 55 | Write-Host "`t `t" $DiskPath "`n" 56 | 57 | <#Write-Host "Permissions: `t" -ForegroundColor Gray -NoNewline 58 | Write-Host "`t `t" $permissions "`n"#> 59 | } 60 | 61 | function updateAPIConfigFile { 62 | 63 | $api__flex_asset_type_id = $api_config.flexible_asset_type_id 64 | 65 | $api__key_name_ShareName = $api_config.key_name_ShareName 66 | $api__key_name_ShareDescription = $api_config.key_name_ShareDescription 67 | $api__key_name_Server = $api_config.key_name_Server 68 | $api__key_name_SharePath = $api_config.key_name_SharePath 69 | $api__key_name_DiskPath = $api_config.key_name_DiskPath 70 | $api__key_name_Permissions = $api_config.key_name_Permissions 71 | 72 | 73 | @" 74 | @{ 75 | org_id = '$api__org_id' 76 | flexible_asset_type_id = '$api__flex_asset_type_id' 77 | 78 | key_name_ShareName = '$api__key_name_ShareName' 79 | key_name_ShareDescription = '$api__key_name_ShareDescription' 80 | key_name_Server = '$api__key_name_Server' 81 | key_name_SharePath = '$api__key_name_SharePath' 82 | key_name_DiskPath = '$api__key_name_DiskPath' 83 | key_name_Permissions = '$api__key_name_Permissions' 84 | } 85 | "@ | Out-File -FilePath $api -Force 86 | } 87 | 88 | function formatAPIData { 89 | 90 | $api__flex_asset_type_id = $api_config.flexible_asset_type_id 91 | 92 | $api__key_name_ShareName = $api_config.key_name_ShareName 93 | $api__key_name_ShareDescription = $api_config.key_name_ShareDescription 94 | $api__key_name_Server = $api_config.key_name_Server 95 | $api__key_name_SharePath = $api_config.key_name_SharePath 96 | $api__key_name_DiskPath = $api_config.key_name_DiskPath 97 | $api__key_name_Permissions = $api_config.key_name_Permissions 98 | 99 | 100 | if($api_config.org_id) { 101 | $api__org_id = $api_config.org_id 102 | } 103 | elseif($organization) { 104 | 105 | Write-Host "No organization id was specified in the config file, attempting an ` 106 | auto-match based on the name: " $organization -ForegroundColor Yellow 107 | 108 | $attempted_match = Get-ITGlueOrganizations -filter_name "$organization" 109 | 110 | if($attempted_match.data[0].attributes.name -eq $organization) { 111 | Write-Host "Auto-match successful. Updating config file with organization id." -ForegroundColor Green 112 | 113 | $api__org_id = $attempted_match.data.id 114 | 115 | updateAPIConfigFile 116 | 117 | } 118 | else { 119 | Write-Error "No auto-match was found. Please pass the exact name to -organization or ` 120 | add the organization id to the config file." 121 | 122 | return 123 | } 124 | } 125 | else { 126 | Write-Error "No organization id was found. Please add an organization id to the config file ` 127 | or attempt a match by putting the full name in the -organization parameter." 128 | 129 | return 130 | } 131 | 132 | $api__Server_id = (Get-ITGlueConfigurations -filter_organization_id $api__org_id -filter_name $currentServer)[0].id 133 | 134 | $api__body = @{ 135 | type = "flexible_assets" 136 | attributes = @{ 137 | organization_id = $api__org_id 138 | flexible_asset_type_id = $api_config.flexible_asset_type_id 139 | traits = @{ 140 | $api__key_name_ShareName = $share 141 | $api__key_name_ShareDescription = $ShareDescription 142 | $api__key_name_Server = $api__Server_id 143 | $api__key_name_SharePath = $writePath 144 | $api__key_name_DiskPath = $DiskPath 145 | $api__key_name_Permissions = $permissions 146 | } 147 | } 148 | } 149 | 150 | return $api__body 151 | } 152 | 153 | if($help) { 154 | Get-Help $MyInvocation.MyCommand.Path 155 | exit 156 | } 157 | 158 | if(($silent) -and !($api -or $file)) { 159 | Write-Error -Message "ERROR: Using the silent flag requires a location to save results to." ` 160 | -Category InvalidOperation ` 161 | } 162 | else { 163 | if($continuum) { 164 | $organization = (Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\SAAZOD").SITENAME 165 | } 166 | 167 | $computer = $env:COMPUTERNAME 168 | $SaveData = @() 169 | 170 | $Files = gwmi -Class win32_share -ComputerName $computer -Filter "Type=0" | Where-Object{$_.Name -NotMatch "^print|^NETLOGON|^MTATempStore|^prnproc"} 171 | $shares = $Files| select -ExpandProperty Name 172 | $description = $Files| select -ExpandProperty Description 173 | $path = $Files| select -ExpandProperty Path 174 | $server= ([regex]::matches($Files, "(?<=[\\][\\])[^\\]+")) 175 | 176 | $i=0 177 | foreach ($share in $shares) { 178 | #if( $shares -notlike "print$" -or $shares -notlike "NETLOGON" -or $shares -notlike "MTATempStore$"){ 179 | $acl = $null # or $sharePath[$i] 180 | 181 | $permissions= "" 182 | Write-Host $share -ForegroundColor Green 183 | Write-Host $('-' * $share.Length) -ForegroundColor Green 184 | $currentServer= $server[$i] 185 | $writePath = "\\$currentServer\$share" 186 | 187 | 188 | 189 | $files = Get-WMIObject -Class Win32_LogicalShareSecuritySetting -Filter "name='$Share'" -ComputerName $computer | where-Object {$share -NotLike "print$" -or $share -NotLike "NETLOGON" -or $share -NotLike "MTATempStore$"} 190 | if($files){ 191 | $obj = @() 192 | $ACLS = $files.GetSecurityDescriptor().Descriptor.DACL 193 | foreach($ACL in $ACLS){ 194 | $User = $ACL.Trustee.Name 195 | if(!($user)){$user = $ACL.Trustee.SID} #If there is no username use SID 196 | $Domain = $ACL.Trustee.Domain 197 | switch($ACL.AccessMask) { 198 | 2032127 {$Perm = "Full Control"} 199 | 1245631 {$Perm = "Change"} 200 | 1179817 {$Perm = "Read"} 201 | } 202 | $permissions= $permissions + "

$Domain\$user $Perm

" 203 | } # End foreach $ACL 204 | $ShareDescription= $description[$i] 205 | $DiskPath= $path[$i] 206 | 207 | if(!$silent){writeOutput} 208 | 209 | if($url -or $files) { 210 | $PostData = @{ 211 | #"Organization" = "$organization" 212 | "Share Name" = "$share" 213 | "Share Description" = "$ShareDescription" 214 | "Server" = "$currentServer" 215 | "Share Path" = "$writePath" 216 | "Disk Path" = "$DiskPath" 217 | #"Permissions" = "$permissions" 218 | } 219 | } 220 | if($file) { 221 | $SaveData += New-Object PSObject -Property $PostData 222 | } 223 | if($api) { 224 | try { 225 | Import-Module ITGlueAPI 226 | } 227 | catch { 228 | Write-Error "ERROR: The IT Glue API PowerShell module cannot be imported." 229 | Write-Error "Please download it from https://github.com/itglue/powershellwrapper, configure it, and try again." 230 | } 231 | 232 | if(test-path $api) { 233 | $api_config = Import-LocalizedData -FileName "$api" 234 | 235 | Write-Host "File Shares flex asset configuration file found!" -ForegroundColor Green 236 | 237 | $api__body = formatAPIData # format data for API call 238 | $api__org_id = $api__body.data.attributes.organization_id 239 | $api__flex_asset_id = $api_config.flex_asset_id 240 | 241 | if($api__org_id) { 242 | Write-Host "Creating a new flexible asset." 243 | 244 | $api__output_data = New-ITGlueFlexibleAssets -data $api__body 245 | 246 | $api__output_data 247 | } 248 | } 249 | else { 250 | Write-Error "ERROR: File Shares flex asset configuration file was found. Please create one and re-run the script." 251 | } 252 | } 253 | 254 | $i++ 255 | }# end if $file 256 | #}# end if(notlike) 257 | } # end foreach $share 258 | if($file){ 259 | $SaveData | export-csv -Path $file -NoTypeInformation 260 | } 261 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Active Directory/ActiveDirectory.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | 3 | .SYNOPSIS 4 | This script grabs all domains in the current forest along with servers hosting all FSMO roles for each domain 5 | 6 | .DESCRIPTION 7 | Options: 8 | 9 | -help - Display the current help menu 10 | -silent - Run the script without printing anything 11 | -FQDN - Show Fully Qualified Domain Name (server.domain.tld) instead of hostname 12 | -Organization - Attempt an auto-match based on organization name (must be an exact match to what exists in IT Glue) 13 | -api - Declare a file name for an API config file to post flex asset directly to IT Glue 14 | -file - Declare a location to save script output to as a csv 15 | 16 | .EXAMPLE 17 | ./ADScraper.ps1 -s -api "api_config-ActiveDirectory.ps1" 18 | ./ADScraper.ps1 -FQDN -file "C:\adout.csv" 19 | 20 | .NOTES 21 | Author: Caleb Albers 22 | 23 | If you wish to use the -api parameter to upload results directly to IT Glue, make sure you have the IT Glue PowerShell module installed and configured (https://github.com/itglue/powershellwrapper) 24 | 25 | .LINK 26 | https://github.com/itglue/automation 27 | 28 | #> 29 | 30 | Param ( 31 | [switch]$help = $False, 32 | [switch]$silent = $False, 33 | [switch]$FQDN = $False, 34 | [string]$api = "", 35 | [string]$file = "", 36 | [string]$organization = "" 37 | ) 38 | 39 | 40 | try { 41 | Import-Module ActiveDirectory 42 | } 43 | catch { 44 | Write-Error "The Active Directory module could not be imported. Please make sure it is installed." 45 | } 46 | 47 | 48 | # Print results 49 | function writeOutput { 50 | Write-Host "Organization Name... `t" -ForegroundColor Gray -NoNewline 51 | Write-Host "`t `t" $organization "`n" 52 | 53 | Write-Host "Forest Name... `t `t" -ForegroundColor Gray -NoNewline 54 | Write-Host "`t" $ADForestName "`n" 55 | 56 | Write-Host "Getting AD Functional Level..." -ForegroundColor Gray -NoNewline 57 | Write-Host "`t `t" $ADFunctionalLevel "`n" 58 | 59 | Write-Host "Getting AD Full Name... " -ForegroundColor Green -NoNewline 60 | Write-Host "`t `t" $Domain "`n" 61 | 62 | Write-Host "Getting AD Short Name... `t" -ForegroundColor Green -NoNewline 63 | Write-Host "`t" $ADShortName "`n" 64 | 65 | Write-Host "Getting FSMO Roles..." -ForegroundColor Green 66 | 67 | Write-Host "`t Schema Master: `t " -ForegroundColor Yellow -NoNewline 68 | Write-Host $SchemaMaster 69 | 70 | Write-Host "`t Domain Naming Master: `t " -ForegroundColor Yellow -NoNewline 71 | Write-Host $DomainNamingMaster 72 | 73 | Write-Host "`t Relative ID (RID) Master: `t " -ForegroundColor Yellow -NoNewline 74 | Write-Host $RIDMaster 75 | 76 | Write-Host "`t PDC Emulator: `t " -ForegroundColor Yellow -NoNewline 77 | Write-Host $PDCEmulator 78 | 79 | Write-Host "`t Infrastructure Master: `t " -ForegroundColor Yellow -NoNewline 80 | Write-Host $InfrastructureMaster "`n" 81 | 82 | Write-Host "Getting Global Catalog Servers (Domain Controllers)..." -ForegroundColor Green 83 | $GlobalCatalogs 84 | } 85 | 86 | function updateAPIConfigFile { 87 | 88 | $api__flex_asset_type_id = $api_config.flexible_asset_type_id 89 | 90 | $api__key_name_ADForestName = $api_config.key_name_ADForestName 91 | $api__key_name_ADFunctionalLevel = $api_config.key_name_ADFunctionalLevel 92 | $api__key_name_DomainName = $api_config.key_name_DomainName 93 | $api__key_name_DomainShortName = $api_config.key_name_DomainShortName 94 | $api__key_name_SchemaMaster = $api_config.key_name_SchemaMaster 95 | $api__key_name_DomainNamingMaster = $api_config.key_name_DomainNamingMaster 96 | $api__key_name_RIDMaster = $api_config.key_name_RIDMaster 97 | $api__key_name_PDCEmulator = $api_config.key_name_PDCEmulator 98 | $api__key_name_InfrastructureMaster = $api_config.key_name_InfrastructureMaster 99 | $api__key_name_GlobalCatalogServers = $api_config.key_name_GlobalCatalogServers 100 | 101 | 102 | @" 103 | @{ 104 | org_id = '$api__org_id' 105 | flexible_asset_type_id = '$api__flex_asset_type_id' 106 | 107 | key_name_ADForestName = '$api__key_name_ADForestName' 108 | key_name_ADFunctionalLevel = '$api__key_name_ADFunctionalLevel' 109 | key_name_DomainName = '$api__key_name_DomainName' 110 | key_name_DomainShortName = '$api__key_name_DomainShortName' 111 | key_name_SchemaMaster = '$api__key_name_SchemaMaster' 112 | key_name_DomainNamingMaster = '$api__key_name_DomainNamingMaster' 113 | key_name_RIDMaster = '$api__key_name_RIDMaster' 114 | key_name_PDCEmulator = '$api__key_name_PDCEmulator' 115 | key_name_InfrastructureMaster = '$api__key_name_InfrastructureMaster' 116 | key_name_GlobalCatalogServers = '$api__key_name_GlobalCatalogServers' 117 | 118 | 119 | } 120 | "@ | Out-File -FilePath $api -Force 121 | } 122 | 123 | function formatAPIData { 124 | 125 | $api__flex_asset_id = $api_config.flex_asset_id 126 | $api__flex_asset_type_id = $api_config.flexible_asset_type_id 127 | 128 | $api__key_name_ADForestName = $api_config.key_name_ADForestName 129 | $api__key_name_ADFunctionalLevel = $api_config.key_name_ADFunctionalLevel 130 | $api__key_name_DomainName = $api_config.key_name_DomainName 131 | $api__key_name_DomainShortName = $api_config.key_name_DomainShortName 132 | $api__key_name_SchemaMaster = $api_config.key_name_SchemaMaster 133 | $api__key_name_DomainNamingMaster = $api_config.key_name_DomainNamingMaster 134 | $api__key_name_RIDMaster = $api_config.key_name_RIDMaster 135 | $api__key_name_PDCEmulator = $api_config.key_name_PDCEmulator 136 | $api__key_name_InfrastructureMaster = $api_config.key_name_InfrastructureMaster 137 | $api__key_name_GlobalCatalogServers = $api_config.key_name_GlobalCatalogServers 138 | 139 | 140 | 141 | 142 | if($api_config.org_id) { 143 | $api__org_id = $api_config.org_id 144 | } 145 | elseif($organization) { 146 | 147 | Write-Host "No organization id was specified in the config file, attempting an ` 148 | auto-match based on the name: " $organization -ForegroundColor Yellow 149 | 150 | $attempted_match = Get-ITGlueOrganizations -filter_name "$organization" 151 | 152 | if($attempted_match.data[0].attributes.name -eq $organization) { 153 | Write-Host "Auto-match successful. Updating config file with organization id." -ForegroundColor Green 154 | 155 | $api__org_id = $attempted_match.data.id 156 | 157 | updateAPIConfigFile 158 | 159 | } 160 | else { 161 | Write-Error "No auto-match was found. Please pass the exact name to -organization or ` 162 | add the organization id to the config file." 163 | 164 | return 165 | } 166 | } 167 | else { 168 | Write-Error "No organization id was found. Please add an organization id to the config file ` 169 | or attempt a match by putting the full name in the -organization parameter." 170 | 171 | return 172 | } 173 | 174 | # Get the ID for each configuration 175 | 176 | $api__SchemaMaster_id = (Get-ITGlueConfigurations -filter_organization_id $api__org_id -filter_name $SchemaMaster)[0].data.id 177 | $api__DomainNamingMaster_id = (Get-ITGlueConfigurations -filter_organization_id $api__org_id -filter_name $DomainNamingMaster)[0].data.id 178 | $api__RIDMaster_id = (Get-ITGlueConfigurations -filter_organization_id $api__org_id -filter_name $RIDMaster)[0].data.id 179 | $api__PDCEmulator_id = (Get-ITGlueConfigurations -filter_organization_id $api__org_id -filter_name $PDCEmulator)[0].data.id 180 | $api__InfrastructureMaster_id = (Get-ITGlueConfigurations -filter_organization_id $api__org_id -filter_name $InfrastructureMaster)[0].data.id 181 | 182 | $idx = 0 183 | $tmp_global_catalog_ids = @(0) * $GlobalCatalogs.split(",").Count 184 | 185 | $GlobalCatalogs.split(",") | ForEach { 186 | $tmp_global_catalog_ids[$idx] = (Get-ITGlueConfigurations -filter_organization_id $api__org_id -filter_name $_)[0].data.id 187 | $idx++ 188 | } 189 | 190 | $api__GlobalCatalogs = $tmp_global_catalog_ids 191 | 192 | 193 | $api__body = @{ 194 | type = "flexible_assets" 195 | attributes = @{ 196 | organization_id = $api__org_id 197 | flexible_asset_type_id = $api_config.flexible_asset_type_id 198 | traits = @{ 199 | $api__key_name_ADForestName = $ADForestName 200 | $api__key_name_ADFunctionalLevel = $ADFunctionalLevel 201 | $api__key_name_DomainName = $Domain 202 | $api__key_name_DomainShortName = $ADShortName 203 | $api__key_name_SchemaMaster = $api__SchemaMaster_id 204 | $api__key_name_DomainNamingMaster = $api__DomainNamingMaster_id 205 | $api__key_name_RIDMaster = $api__RIDMaster_id 206 | $api__key_name_PDCEmulator = $api__PDCEmulator_id 207 | $api__key_name_InfrastructureMaster = $api__InfrastructureMaster_id 208 | $api__key_name_GlobalCatalogServers = $api__GlobalCatalogs 209 | } 210 | } 211 | } 212 | 213 | return $api__body 214 | } 215 | 216 | if($help) { 217 | Get-Help $MyInvocation.MyCommand.Path 218 | exit 219 | } 220 | 221 | if(($silent) -and !($url -or $file -or $ftp)) { 222 | Write-Error -Message "ERROR: Using the silent flag requires a URL, FTP server, or location to save results to." ` 223 | -Category InvalidOperation ` 224 | } 225 | else { 226 | if($continuum) { 227 | $organization = (Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\SAAZOD").SITENAME 228 | } 229 | 230 | # Get forest info 231 | if($FQDN) { 232 | $ADForestName = (Get-ADForest).Name 233 | $SchemaMaster = (Get-ADForest).SchemaMaster 234 | $DomainNamingMaster = (Get-ADForest).DomainNamingMaster 235 | } 236 | else { 237 | $ADForestName = ((Get-ADForest).Name).split(".")[0] 238 | $SchemaMaster = ((Get-ADForest).SchemaMaster).split(".")[0] 239 | $DomainNamingMaster = ((Get-ADForest).DomainNamingMaster).split(".")[0] 240 | } 241 | $FullFunctionalLevel = (Get-ADForest).ForestMode 242 | switch($FullFunctionalLevel) { 243 | Windows2000Forest {$ADFunctionalLevel = "2000"} 244 | Windows2003Forest {$ADFunctionalLevel = "2003"} 245 | Windows2008Forest {$ADFunctionalLevel = "2008"} 246 | Windows2008R2Forest {$ADFunctionalLevel = "2008 R2"} 247 | Windows2012Forest {$ADFunctionalLevel = "2012"} 248 | Windows2012R2Forest {$ADFunctionalLevel = "2012 R2"} 249 | Windows2016Forest {$ADFunctionalLevel = "2016"} 250 | } 251 | 252 | # Get Global Catalog Servers (Domain Controllers) 253 | if($FQDN) { 254 | $GlobalCatalogs = (Get-ADForest).GlobalCatalogs -join ',' 255 | } 256 | else { 257 | $GlobalCatalogList = @((Get-ADForest).GlobalCatalogs) 258 | $GlobalCatalogs = "" 259 | for($i = 0; $i -lt ($GlobalCatalogList).Count; $i++) { 260 | $GlobalCatalogs += (($GlobalCatalogList[$i]).split(".")[0]) 261 | if(($i+1) -ne $GlobalCatalogList.Count) { $GlobalCatalogs += ","} 262 | } 263 | } 264 | 265 | # Get domain info 266 | $Domains = (Get-ADForest).domains 267 | foreach($Domain in $Domains) { 268 | $ADShortName = (Get-ADDomain -identity $Domain).Name 269 | 270 | # Get FSMO Roles 271 | if($FQDN) { 272 | $RIDMaster = (Get-ADDomain -identity $Domain).RIDMaster 273 | $PDCEmulator = (Get-ADDOmain -identity $Domain).PDCEmulator 274 | $InfrastructureMaster = (Get-ADDomain -identity $Domain).InfrastructureMaster 275 | } 276 | else { 277 | $RIDMaster = ((Get-ADDomain -identity $Domain).RIDMaster).split(".")[0] 278 | $PDCEmulator = ((Get-ADDOmain -identity $Domain).PDCEmulator).split(".")[0] 279 | $InfrastructureMaster = ((Get-ADDomain -identity $Domain).InfrastructureMaster).split(".")[0] 280 | } 281 | 282 | if(!$silent){writeOutput} 283 | if($file -or $ftp) { 284 | $PostData= @{ 285 | organization = $organization; ` 286 | ForestName =$ADForestName; ` 287 | FunctionalLevel = $ADFunctionalLevel; ` 288 | DomainName= $Domain; ` 289 | DomainShortName= $ADShortName; ` 290 | SchemaMaster= $SchemaMaster; ` 291 | DomainNamingMaster = $DomainNamingMaster; ` 292 | RIDMaster = $RIDMaster; ` 293 | PDCEmulator = $PDCEmulator; ` 294 | InfrastructureMaster = $InfrastructureMaster; ` 295 | GlobalCatalogServers = "$GlobalCatalogs"; 296 | } 297 | } 298 | 299 | if($api) { 300 | try { 301 | Import-Module ITGlueAPI 302 | } 303 | catch { 304 | Write-Error "ERROR: The IT Glue API PowerShell module cannot be imported." 305 | Write-Error "Please download it from https://github.com/itglue/powershellwrapper, configure it, and try again." 306 | } 307 | 308 | if(test-path $api) { 309 | $api_config = Import-LocalizedData -FileName "$api" 310 | 311 | Write-Host "Active Directory flex asset configuration file found!" -ForegroundColor Green 312 | 313 | $api__body = formatAPIData # format data for API call 314 | $api__org_id = $api__body.attributes.organization_id 315 | $api__flexible_asset_type_id = $api_config.flexible_asset_type_id 316 | $api__key_name_DomainName = $api_config.key_name_DomainName 317 | 318 | #find if a flex asset for this domain currently exists 319 | $currentADFlexAssets = (Get-ITGlueFlexibleAssets -filter_flexible_asset_type_id $api__flexible_asset_type_id -filter_organization_id $api__org_id) 320 | 321 | $api__flex_asset_id = '' 322 | if($currentADFlexAssets.data.attributes.traits.${api__key_name_DomainName}) { 323 | $fa_index = [array]::indexof($currentADFlexAssets.data.attributes.traits.${api__key_name_DomainName} ,$Domain) 324 | 325 | if($fa_index -ne '-1') { 326 | $api__flex_asset_id = $currentADFlexAssets.data[$fa_index].id 327 | } 328 | } 329 | 330 | if($api__flex_asset_id -and $api__org_id) { 331 | Write-Host "Flexible Asset id found! Updating the pre-existing flex asset with any new changes." 332 | 333 | (Set-ITGlueFlexibleAssets -id $api__flex_asset_id -data $api__body).data 334 | } 335 | elseif($api__org_id) { 336 | Write-Host "No flexible asset id was found... creating a new flexible asset." 337 | 338 | $api__output_data = New-ITGlueFlexibleAssets -data $api__body 339 | 340 | $api__output_data.data 341 | } 342 | } 343 | else { 344 | Write-Error "ERROR: No Active Directory flex asset configuration file was found. Please create one and re-run the script." 345 | } 346 | } 347 | 348 | if($file) { 349 | $SaveData += New-Object PSObject -Property $PostData 350 | } 351 | 352 | } 353 | if($file){ 354 | $SaveData | export-csv -Path $file -NoTypeInformation 355 | } 356 | } --------------------------------------------------------------------------------