From a5b1eab1f35a623068f7d1e536d9c02945b64f87 Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 14:16:11 +0100 Subject: [PATCH 01/13] [Refactor] Transform all Active Directory scripts --- .../AD Servers (Windows PowerShell).rdfe | 26 - .../AD Servers (Windows PowerShell).rdfx | 2426 +++++++++++++++++ .../Active Directory (Python).rdfe | 27 - .../Active Directory (Python).rdfx | 220 ++ ...Active Directory (Windows PowerShell).rdfe | 1 - ...Active Directory (Windows PowerShell).rdfx | 166 ++ 6 files changed, 2812 insertions(+), 54 deletions(-) delete mode 100644 Dynamic Folder/Active Directory/AD Servers (Windows PowerShell).rdfe create mode 100644 Dynamic Folder/Active Directory/AD Servers (Windows PowerShell).rdfx delete mode 100644 Dynamic Folder/Active Directory/Active Directory (Python).rdfe create mode 100644 Dynamic Folder/Active Directory/Active Directory (Python).rdfx delete mode 100644 Dynamic Folder/Active Directory/Basic Active Directory (Windows PowerShell).rdfe create mode 100644 Dynamic Folder/Active Directory/Basic Active Directory (Windows PowerShell).rdfx diff --git a/Dynamic Folder/Active Directory/AD Servers (Windows PowerShell).rdfe b/Dynamic Folder/Active Directory/AD Servers (Windows PowerShell).rdfe deleted file mode 100644 index 778180f..0000000 --- a/Dynamic Folder/Active Directory/AD Servers (Windows PowerShell).rdfe +++ /dev/null @@ -1,26 +0,0 @@ -{ - "Name": "Dynamic Folder Export", - "Objects": [ - { - "Type": "DynamicFolder", - "Name": "AD Servers - Windows PowerShell", - "Description": "This script allows you to query Active Directory to add computers from your Active Directory environment to RoyalTS.", - "Notes": "\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t

This script requires Windows PowerShell 4.x/5.x as well as the Active Directory

Powershell Cmdlets.

 

This script allows you to query Active Directory to add computers from your Active Directory environment to RoyalTS.

 

To use this application, update the Custom Property ConfigFileName with the name of the configuration file for the dynamic folder.  This allows you to configure multiple dynamic folders using the same script without having to update the Custom Properties multiple times - the only time will be to set the setting file name.  If this field is not updated, the setting file will be set as Settings.xml.

 

Upon launching the form the first time, you are prompted to fill in a few settings.

The first setting is the domain name.  After you type in the domain name, the ldap dc path and Primary Domain Controller Emulator will autopopulate the DC Root and DC fields.  

 

The next field to fill in is the Connection Type dropdown.  This list contains all of the valid connection types the script is able to connect.  Depending on what option is selected other options will appear below the dropdown.  These settings include if the connection should use Cim sessions, what port number to use, and if the connection should be a admin/console connection.

 

The next field to fill in is the Credential Name.  This is the name of the credential in RoyalTS to have the computers open up with.  If you wish to set the credentials at the Dynamic Folder level in the same way of typical folders, you can leave this field blank and all the connections will be set to auto inherit their credentials from the Dynamic Folder.

 

SearchBase takes in the OU Path that the computers should be located in.  You can populate this field by clicking on the button to the right of the text box.  This button will load a GUI to select the correct OU.

 

SearchScope is how to search under the selected OU entered in SearchBase.  The three options under here are:

    \r\n\t\t\t
  1. Base - only computers contained in the selected OU are listed
  2. SubTree - all computers in all of the OUs under the selected OU are listed
  3. OneLevel - all computers in the OUs one level under the selcted OU are listed
\r\n\t\t

 

The filter field allows for adding in filters which are compatible with the PowerShell AD CMDLTS.  By default the filter is * which will return all comptuers.  Example filters are below.

    \r\n\t\t\t
  1. name -like 'test*'
  2. name -eq 'testpd09'
\r\n\t\t

 

After your settings are entered, click Submit to save the data.

 

Every time you run the script to enumerate the computers, the Royal TS Dynamic Folder Configurator dialog will appear.  If the mouse is not moved over the screen within five seconds, the dialog assumes no data needs to be modified for the filter and the current selected filter is accepted.  

 

If the configuration file is missing and cannot be loaded by the script, then the dialog will not automatically close as these settings are required to produce a list of computers.

 

Configuration Walkthrough Video: https://youtu.be/wMnqSQd1tYU

 

Version: 1.1

Author: Paul DeArment Jr

Twitter: pdearmen

Github: https://github.com/armentpau

\r\n\r\n", - "CustomProperties": [ - { - "Name": "ConfigFileName", - "Type": "Text", - "Value": "TODO" - }, - { - "Name": "ConfigFilePath", - "Type": "Text", - "Value": "TODO" - } - ], - "Script": "#------------------------------------------------------------------------\r\n# Source File Information (DO NOT MODIFY)\r\n# Source ID: 77e8c89d-ff4b-4c60-9453-7691ab39cb9f\r\n# Source File: ..\\RoyalTSDynamicForm\\RoyalTSDynamicForm.psproj\r\n#------------------------------------------------------------------------\r\n#region Project Recovery Data (DO NOT MODIFY)\r\n<#RecoveryData:\r\nrQIAAB+LCAAAAAAABACdUtFOgzAUfV+yfyB9NGEMN7cRWR/MgtmDzozN16WUi6ClJaXM4ddbKJiZ\r\naUx8ue25vfec3tP6W6DiCLJeEUXwcGBZ/pMUr0CVFdacplLw7APiJQoIKwG1ySBjCuQSXY2K0r1t\r\nYm6W2CzuKWftJmljqaPJpMCKkTop1AppqWeQZSY4vh65vtOD7kyrwHqF53NY0IUX20kyjewpnY1t\r\nb3ozseczzyXRxKORl/hOV9y1dhPs6gLw2HfOYU8uWKzlLOdcrexAB627KmN68jHCoSJSVUUzjNH6\r\nrdIKUyIbu3ay0m5tIQEJnEJQcar0cEu05kfxBvY9ExFhB20WwmZfNs79wf4DX5iKd/uBZDwQMtd8\r\nCcI9al7gn4Sb/SEEpk0T0nBu9lafuKA1wLj35bZBG5m9ZJywpuCR5IC3oiZsF65qTvKMdrcsdIvv\r\nXNQOB77z7Xt+AjQsCuytAgAA#>\r\n#endregion\r\n<#\r\n .NOTES\r\n --------------------------------------------------------------------------------\r\n Code generated by: SAPIEN Technologies, Inc., PowerShell Studio 2019 v5.6.156\r\n Generated on: 12/31/2018 1:42 PM\r\n Generated by: Paul DeArment\r\n --------------------------------------------------------------------------------\r\n .DESCRIPTION\r\n Script generated by PowerShell Studio 2019\r\n#>\r\n\r\n\r\n\r\n#region Source: Startup.pss\r\n#region File Recovery Data (DO NOT MODIFY)\r\n<#RecoveryData:\r\nXwAAAB+LCAAAAAAABACzCUpNzi9LLap0SSxJVAAyijPz82yVjPUMley4FBRs/Isy0zPzEnPcMnNS\r\n/RJzU+2CSxKLSkoL9AqKi230MWS5bPSRDbQDAHEtMNxfAAAA#>\r\n#endregion\r\n#----------------------------------------------\r\n#region Import Assemblies\r\n#----------------------------------------------\r\n#endregion Import Assemblies\r\n\r\n#Define a Param block to use custom parameters in the project\r\n#Param ($CustomParameter)\r\n\r\nfunction Main\r\n{\r\n<#\r\n .SYNOPSIS\r\n The Main function starts the project application.\r\n \r\n .PARAMETER Commandline\r\n $Commandline contains the complete argument string passed to the script packager executable.\r\n \r\n .NOTES\r\n Use this function to initialize your script and to call GUI forms.\r\n\t\t\r\n .NOTES\r\n To get the console output in the Packager (Forms Engine) use: \r\n\t\t$ConsoleOutput (Type: System.Collections.ArrayList)\r\n#>\r\n\tParam ([String]$Commandline)\r\n\t\r\n\tif ((Show-MainForm_psf) -eq 'OK')\r\n\t{\r\n\t\t\r\n\t}\r\n\t\r\n\t$script:ExitCode = 0 #Set the exit code for the Packager\r\n}\r\n#endregion Source: Startup.pss\r\n\r\n#region Source: Globals.ps1\r\n\t#--------------------------------------------\r\n\t# Declare Global Variables and Functions here\r\n\t#--------------------------------------------\r\n\t\r\n\t#the below are the default port numbers for the various connection methods\r\n\t#this is done through a hash table to allow for easily being able to update the port assignments\r\n\t#should that be needed as well as ability to easily and quickly look up the data using the has table\r\n\t$hashPorts = @{\r\n\t\t\"SecureGateway\" = 22\r\n\t\t\"RoyalServer\" = 54899 \r\n\t\t\"RemoteDesktopGateway\" = $null\r\n\t\t\"RemoteDesktopConnection\" = 3389\r\n\t\t\"TerminalConnection - SSH\" = 22\r\n\t\t\"TerminalConnection - Telnet\" = 23\r\n\t\t\"TerminalConnection - Serial\" = $null\r\n\t\t\"VNCConnection\" = 5900\r\n\t\t\"WindowsEventsConnection\" = $null\r\n\t\t\"WindowsServicesConnection\" = $null\r\n\t\t\"WindowsProcessesConnection\" = $null\r\n\t\t\"TerminalServicesConnection\" = $null\r\n\t\t\"PowerShellConnection\"\t = $null\r\n\t}\r\n\t\r\n\tfunction Update-DCTextBoxes\r\n\t{\r\n\t\tif (-not ([string]::IsNullOrEmpty($domainTextBox.Text)))\r\n\t\t{\r\n\t\t\ttry\r\n\t\t\t{\r\n\t\t\t\t$selectedDomain = Get-ADDomain -Identity $($domainTextBox.text) -ErrorAction Stop\r\n\t\t\t\t$dcRootTextBox.text = $selectedDomain.distinguishedname\r\n\t\t\t\t$dcTextBox.Text = $selectedDomain.pdcemulator\r\n\t\t\t}\r\n\t\t\tcatch\r\n\t\t\t{\r\n\t\t\t\t\r\n\t\t\t}\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t$dcRootTextBox.Text = \"\"\r\n\t\t\t$dcTextBox.Text = \"\"\r\n\t\t}\r\n\t}\r\n\t\r\n\tfunction Start-showOUDialogs\r\n\t{\r\n\t\tif (-not [string]::IsNullOrEmpty($dcRootTextBox.Text))\r\n\t\t{\r\n\t\t\t$script:currentlySelectedOU = $searchBaseTextBox.text\r\n\t\t\t$script:selectedDomainRoot = $dcRootTextBox.text\r\n\t\t\tShow-OU_Selector_psf\r\n\t\t\t$searchBaseTextBox.Text = $script:selectedOU\r\n\t\t}\r\n\t}\r\n\t\r\n#endregion Source: Globals.ps1\r\n\r\n#region Source: MainForm.psf\r\nfunction Show-MainForm_psf\r\n{\r\n#region File Recovery Data (DO NOT MODIFY)\r\n<#RecoveryData:\r\n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#>\r\n#endregion\r\n\t#----------------------------------------------\r\n\t#region Import the Assemblies\r\n\t#----------------------------------------------\r\n\t[void][reflection.assembly]::Load('System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')\r\n\t[void][reflection.assembly]::Load('System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')\r\n\t#endregion Import Assemblies\r\n\r\n\t#----------------------------------------------\r\n\t#region Generated Form Objects\r\n\t#----------------------------------------------\r\n\t[System.Windows.Forms.Application]::EnableVisualStyles()\r\n\t$MainForm = New-Object 'System.Windows.Forms.Form'\r\n\t$checkboxAdminConsole = New-Object 'System.Windows.Forms.CheckBox'\r\n\t$OUNameButton = New-Object 'System.Windows.Forms.Button'\r\n\t$checkboxUseCim = New-Object 'System.Windows.Forms.CheckBox'\r\n\t$portNumberTextBox = New-Object 'System.Windows.Forms.TextBox'\r\n\t$labelPortNumber = New-Object 'System.Windows.Forms.Label'\r\n\t$labelConnectionType = New-Object 'System.Windows.Forms.Label'\r\n\t$connectionTypeDropDown = New-Object 'System.Windows.Forms.ComboBox'\r\n\t$credentialTextBox = New-Object 'System.Windows.Forms.TextBox'\r\n\t$labelCredentialName = New-Object 'System.Windows.Forms.Label'\r\n\t$labelPDC = New-Object 'System.Windows.Forms.Label'\r\n\t$dcTextBox = New-Object 'System.Windows.Forms.TextBox'\r\n\t$buttonSubmit = New-Object 'System.Windows.Forms.Button'\r\n\t$domainTextBox = New-Object 'System.Windows.Forms.TextBox'\r\n\t$labelDCRoot = New-Object 'System.Windows.Forms.Label'\r\n\t$dcRootTextBox = New-Object 'System.Windows.Forms.TextBox'\r\n\t$labelDomainName = New-Object 'System.Windows.Forms.Label'\r\n\t$searchBaseTextBox = New-Object 'System.Windows.Forms.TextBox'\r\n\t$filterTextBox = New-Object 'System.Windows.Forms.TextBox'\r\n\t$labelFilter = New-Object 'System.Windows.Forms.Label'\r\n\t$labelSearchScope = New-Object 'System.Windows.Forms.Label'\r\n\t$scopeComboBox = New-Object 'System.Windows.Forms.ComboBox'\r\n\t$labelSearchBase = New-Object 'System.Windows.Forms.Label'\r\n\t$keepSettingTimer = New-Object 'System.Windows.Forms.Timer'\r\n\t$infoToolTip = New-Object 'System.Windows.Forms.ToolTip'\r\n\t$InitialFormWindowState = New-Object 'System.Windows.Forms.FormWindowState'\r\n\t#endregion Generated Form Objects\r\n\r\n\t#----------------------------------------------\r\n\t# User Generated Script\r\n\t#----------------------------------------------\r\n\tImport-Module ActiveDirectory\r\n\t\r\n\t$MainForm_Load = {\r\n\t\t$scopeComboBox.SelectedItem = \"Subtree\"\r\n\t\t$connectionTypeDropDown.SelectedItem = \"RemoteDesktopConnection\"\r\n#\t\t$script:ConfigFilePath = \"$CustomProperty.ConfigFilePath$\\RoyalTSDynamicFolderCustomizer\"\r\n\t\t\r\n\t\tif (\"$CustomProperty.ConfigFilePath$\" -ne '.ConfigFilePath$' -and \"$CustomProperty.ConfigFilePath$\" -ne \"TODO\")\r\n\t\t{\r\n\t\t\t$script:ConfigFilePath = \"$CustomProperty.ConfigFilePath$\"\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t$script:ConfigFilePath = \"$($env:APPDATA)\\RoyalTSDynamicFolderCustomizer\"\r\n\t\t}\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\tif (\"$CustomProperty.ConfigFileName$\" -ne '.ConfigFileName$' -and \"$CustomProperty.ConfigFileName$\" -ne \"TODO\")\r\n\t\t{\r\n\t\t\t$script:configFileName = \"$CustomProperty.ConfigFileName$\"\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t$script:configFileName = \"settings.xml\"\r\n\t\t}\r\n\t\t\r\n\t\tif (-not (Test-Path $script:ConfigFilePath))\r\n\t\t{\r\n\t\t\ttry\r\n\t\t\t{\r\n\t\t\t\tNew-Item -ItemType directory -Path $script:ConfigFilePath -ErrorAction Stop\r\n\t\t\t}\r\n\t\t\tcatch\r\n\t\t\t{\r\n\t\t\t\texit\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (Test-Path \"$($script:ConfigFilePath)\\$($configFileName)\")\r\n\t\t{\r\n\t\t\t$data = Import-Clixml -Path \"$($script:ConfigFilePath)\\$($configFileName)\"\r\n\t\t\t$domainTextBox.Text = $data.domainData\r\n\t\t\tUpdate-DCTextBoxes\r\n\t\t\t$searchBaseTextBox.Text = $data.searchbase\r\n\t\t\t$filterTextBox.Text = $data.filter\r\n\t\t\t$credentialTextBox.Text = $data.credentialname\r\n\t\t\t$scopeComboBox.SelectedItem = $data.searchscope\r\n\t\t\t$keepSettingTimer.Enabled = $true\r\n\t\t\t$checkboxUseCim.CheckState = $data.useCimChecked\r\n\t\t\t$connectionTypeDropDown.SelectedItem = $data.connectionType\r\n\t\t\t$portNumberTextBox.Text = $data.portnumber\r\n\t\t\t$checkboxAdminConsole.CheckState = $data.adminConsole\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t$keepSettingTimer.Enabled = $false\r\n\t\t}\r\n\t}\r\n\t\r\n\tfunction Update-ComboBox\r\n\t{\t\r\n\t\tparam\r\n\t\t(\r\n\t\t\t[Parameter(Mandatory = $true)]\r\n\t\t\t[ValidateNotNull()]\r\n\t\t\t[System.Windows.Forms.ComboBox]\r\n\t\t\t$ComboBox,\r\n\t\t\t[Parameter(Mandatory = $true)]\r\n\t\t\t[ValidateNotNull()]\r\n\t\t\t$Items,\r\n\t\t\t[Parameter(Mandatory = $false)]\r\n\t\t\t[string]$DisplayMember,\r\n\t\t\t[Parameter(Mandatory = $false)]\r\n\t\t\t[string]$ValueMember,\r\n\t\t\t[switch]\r\n\t\t\t$Append\r\n\t\t)\r\n\t\t\r\n\t\tif (-not $Append)\r\n\t\t{\r\n\t\t\t$ComboBox.Items.Clear()\r\n\t\t}\r\n\t\t\r\n\t\tif ($Items -is [Object[]])\r\n\t\t{\r\n\t\t\t$ComboBox.Items.AddRange($Items)\r\n\t\t}\r\n\t\telseif ($Items -is [System.Collections.IEnumerable])\r\n\t\t{\r\n\t\t\t$ComboBox.BeginUpdate()\r\n\t\t\tforeach ($obj in $Items)\r\n\t\t\t{\r\n\t\t\t\t$ComboBox.Items.Add($obj)\r\n\t\t\t}\r\n\t\t\t$ComboBox.EndUpdate()\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t$ComboBox.Items.Add($Items)\r\n\t\t}\r\n\t\t\r\n\t\t$ComboBox.DisplayMember = $DisplayMember\r\n\t\t$ComboBox.ValueMember = $ValueMember\r\n\t}\r\n\t\r\n\t$keepSettingTimer_Tick={\r\n\t\t$MainForm.close()\r\n\t}\r\n\t\r\n\t$MainForm_MouseMove=[System.Windows.Forms.MouseEventHandler]{\r\n\t\t$keepSettingTimer.Enabled = $false\r\n\t}\r\n\t\r\n\t$searchBaseTextBox_MouseDoubleClick=[System.Windows.Forms.MouseEventHandler]{\r\n\t\tStart-showOUDialogs\r\n\t}\r\n\t\r\n\t$buttonSubmit_Click={\r\n\t\t$MainForm.close()\t\r\n\t}\r\n\t\r\n\t$MainForm_KeyDown=[System.Windows.Forms.KeyEventHandler]{\r\n\t\t$keepSettingTimer.Enabled = $false\t\r\n\t}\r\n\t\r\n\t$searchBaseTextBox_KeyDown=[System.Windows.Forms.KeyEventHandler]{\r\n\t\t$keepSettingTimer.Enabled = $false\r\n\t}\r\n\t\r\n\t$scopeComboBox_KeyDown=[System.Windows.Forms.KeyEventHandler]{\r\n\t\t$keepSettingTimer.Enabled = $false\r\n\t}\r\n\t\r\n\t$filterTextBox_KeyDown=[System.Windows.Forms.KeyEventHandler]{\r\n\t\t$keepSettingTimer.Enabled = $false\r\n\t}\r\n\t\r\n\t$domainTextBox_KeyDown=[System.Windows.Forms.KeyEventHandler]{\r\n\t\t$keepSettingTimer.Enabled = $false\r\n\t}\r\n\t$domainTextBox_Leave={\r\n\t\tUpdate-DCTextBoxes\r\n\t}\r\n\t\r\n\t$connectionTypeDropDown_SelectedIndexChanged={\r\n\t\t$portNumberTextBox.Text = $hashPorts[$($connectionTypeDropDown.text)]\r\n\t\tif ($connectionTypeDropDown.text -like \"RemoteDesktopConnection\")\r\n\t\t{\r\n\t\t\t$checkboxAdminConsole.Visible = $true\r\n\t\t\t$checkboxUseCim.Visible = $false\r\n\t\t\t$labelPortNumber.Visible = $true\r\n\t\t\t$portNumberTextBox.Visible = $true\r\n\t\t}\r\n\t\telseif ($connectionTypeDropDown.text -like \"remotedesktopgateway\" -or $connectionTypeDropDown.text -like \"terminalconnection - serial\" -or $connectionTypeDropDown.text -like \"terminalservicesconnection\" -or $connectionTypeDropDown.text -like \"powershellconnection\")\r\n\t\t{\r\n\t\t\t$checkboxUseCim.Visible = $false\r\n\t\t\t$labelPortNumber.Visible = $false\r\n\t\t\t$portNumberTextBox.Visible = $false\r\n\t\t\t$checkboxAdminConsole.Visible = $false\r\n\t\t}\r\n\t\telseif($connectionTypeDropDown.Text -like \"WindowsEventsConnection\" -or $connectionTypeDropDown.Text -like \"WindowsServicesConnection\" -or $connectionTypeDropDown.Text -like \"WindowsProcessesConnection\")\r\n\t\t{\r\n\t\t\t$checkboxUseCim.Visible = $true\r\n\t\t\t$labelPortNumber.Visible = $false\r\n\t\t\t$portNumberTextBox.Visible = $false\r\n\t\t\t$checkboxAdminConsole.Visible = $false\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t$checkboxUseCim.Visible = $false\r\n\t\t\t$labelPortNumber.Visible = $true\r\n\t\t\t$portNumberTextBox.Visible = $true\r\n\t\t\t$checkboxUseCim.Checked = $false\r\n\t\t\t$checkboxAdminConsole.Visible = $false\r\n\t\t}\r\n\t}\r\n\t\r\n\t$MainForm_FormClosing = [System.Windows.Forms.FormClosingEventHandler]{\r\n\t\tUpdate-DCTextBoxes\r\n\t\tif ([string]::IsNullOrEmpty($credentialTextBox.text))\r\n\t\t{\r\n\t\t\t$parentCred = $true\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t$parentCred = $false\r\n\t\t}\r\n\t\tNew-Object -TypeName System.Management.Automation.PSObject -Property @{\r\n\t\t\t\"Filter\" = $filterTextBox.Text\r\n\t\t\t\"searchBase\" = $searchBaseTextBox.Text\r\n\t\t\t\"SearchScope\" = $scopeComboBox.Text\r\n\t\t\t\"Server\" = $dcTextBox.text\r\n\t\t\t\"domainData\" = $domainTextBox.text\r\n\t\t\t\"credentialName\" = $credentialTextBox.Text\r\n\t\t\t\"portNumber\" = $portNumberTextBox.Text\r\n\t\t\t\"connectionType\" = $connectionTypeDropDown.Text\r\n\t\t\t\"useCimChecked\" = $checkboxUseCim.CheckState\r\n\t\t\t\"adminConsole\" = $checkboxAdminConsole.CheckState\r\n\t\t\t\"useParentCred\" = $parentCred\r\n\t\t} | Export-Clixml -Path \"$($script:ConfigFilePath)\\$($script:configFileName)\"\r\n\t}\r\n\t\r\n\t$labelSearchBase_Click={\r\n\t\tStart-showOUDialogs\r\n\t}\r\n\t\r\n\t$OUNameButton_Click={\r\n\t\tStart-showOUDialogs\r\n\t}\r\n\t$dcRootTextBox_TextChanged={\r\n\t\tif (-not ([string]::IsNullOrEmpty($dcRootTextBox.Text)))\r\n\t\t{\r\n\t\t\t$OUNameButton.Enabled = $true\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t$OUNameButton.Enabled = $false\r\n\t\t}\r\n\t\t$script:selectedDomainRoot = $dcRootTextBox.Text\r\n\t}\r\n\t\r\n\t# --End User Generated Script--\r\n\t#----------------------------------------------\r\n\t#region Generated Events\r\n\t#----------------------------------------------\r\n\t\r\n\t$Form_StateCorrection_Load=\r\n\t{\r\n\t\t#Correct the initial state of the form to prevent the .Net maximized form issue\r\n\t\t$MainForm.WindowState = $InitialFormWindowState\r\n\t}\r\n\t\r\n\t$Form_StoreValues_Closing=\r\n\t{\r\n\t\t#Store the control values\r\n\t\t$script:MainForm_checkboxAdminConsole = $checkboxAdminConsole.Checked\r\n\t\t$script:MainForm_checkboxUseCim = $checkboxUseCim.Checked\r\n\t\t$script:MainForm_portNumberTextBox = $portNumberTextBox.Text\r\n\t\t$script:MainForm_connectionTypeDropDown = $connectionTypeDropDown.Text\r\n\t\t$script:MainForm_connectionTypeDropDown_SelectedItem = $connectionTypeDropDown.SelectedItem\r\n\t\t$script:MainForm_credentialTextBox = $credentialTextBox.Text\r\n\t\t$script:MainForm_dcTextBox = $dcTextBox.Text\r\n\t\t$script:MainForm_domainTextBox = $domainTextBox.Text\r\n\t\t$script:MainForm_dcRootTextBox = $dcRootTextBox.Text\r\n\t\t$script:MainForm_searchBaseTextBox = $searchBaseTextBox.Text\r\n\t\t$script:MainForm_filterTextBox = $filterTextBox.Text\r\n\t\t$script:MainForm_scopeComboBox = $scopeComboBox.Text\r\n\t\t$script:MainForm_scopeComboBox_SelectedItem = $scopeComboBox.SelectedItem\r\n\t}\r\n\r\n\t\r\n\t$Form_Cleanup_FormClosed=\r\n\t{\r\n\t\t#Remove all event handlers from the controls\r\n\t\ttry\r\n\t\t{\r\n\t\t\t$OUNameButton.remove_Click($OUNameButton_Click)\r\n\t\t\t$connectionTypeDropDown.remove_SelectedIndexChanged($connectionTypeDropDown_SelectedIndexChanged)\r\n\t\t\t$buttonSubmit.remove_Click($buttonSubmit_Click)\r\n\t\t\t$domainTextBox.remove_KeyDown($domainTextBox_KeyDown)\r\n\t\t\t$domainTextBox.remove_Leave($domainTextBox_Leave)\r\n\t\t\t$dcRootTextBox.remove_TextChanged($dcRootTextBox_TextChanged)\r\n\t\t\t$searchBaseTextBox.remove_KeyDown($searchBaseTextBox_KeyDown)\r\n\t\t\t$filterTextBox.remove_KeyDown($filterTextBox_KeyDown)\r\n\t\t\t$scopeComboBox.remove_KeyDown($scopeComboBox_KeyDown)\r\n\t\t\t$MainForm.remove_FormClosing($MainForm_FormClosing)\r\n\t\t\t$MainForm.remove_Load($MainForm_Load)\r\n\t\t\t$MainForm.remove_KeyDown($MainForm_KeyDown)\r\n\t\t\t$MainForm.remove_MouseMove($MainForm_MouseMove)\r\n\t\t\t$keepSettingTimer.remove_Tick($keepSettingTimer_Tick)\r\n\t\t\t$MainForm.remove_Load($Form_StateCorrection_Load)\r\n\t\t\t$MainForm.remove_Closing($Form_StoreValues_Closing)\r\n\t\t\t$MainForm.remove_FormClosed($Form_Cleanup_FormClosed)\r\n\t\t}\r\n\t\tcatch { Out-Null <# Prevent PSScriptAnalyzer warning #> }\r\n\t}\r\n\t#endregion Generated Events\r\n\r\n\t#----------------------------------------------\r\n\t#region Generated Form Code\r\n\t#----------------------------------------------\r\n\t$MainForm.SuspendLayout()\r\n\t#\r\n\t# MainForm\r\n\t#\r\n\t$MainForm.Controls.Add($checkboxAdminConsole)\r\n\t$MainForm.Controls.Add($OUNameButton)\r\n\t$MainForm.Controls.Add($checkboxUseCim)\r\n\t$MainForm.Controls.Add($portNumberTextBox)\r\n\t$MainForm.Controls.Add($labelPortNumber)\r\n\t$MainForm.Controls.Add($labelConnectionType)\r\n\t$MainForm.Controls.Add($connectionTypeDropDown)\r\n\t$MainForm.Controls.Add($credentialTextBox)\r\n\t$MainForm.Controls.Add($labelCredentialName)\r\n\t$MainForm.Controls.Add($labelPDC)\r\n\t$MainForm.Controls.Add($dcTextBox)\r\n\t$MainForm.Controls.Add($buttonSubmit)\r\n\t$MainForm.Controls.Add($domainTextBox)\r\n\t$MainForm.Controls.Add($labelDCRoot)\r\n\t$MainForm.Controls.Add($dcRootTextBox)\r\n\t$MainForm.Controls.Add($labelDomainName)\r\n\t$MainForm.Controls.Add($searchBaseTextBox)\r\n\t$MainForm.Controls.Add($filterTextBox)\r\n\t$MainForm.Controls.Add($labelFilter)\r\n\t$MainForm.Controls.Add($labelSearchScope)\r\n\t$MainForm.Controls.Add($scopeComboBox)\r\n\t$MainForm.Controls.Add($labelSearchBase)\r\n\t$MainForm.AcceptButton = $buttonSubmit\r\n\t$MainForm.AutoScaleDimensions = '6, 13'\r\n\t$MainForm.AutoScaleMode = 'Font'\r\n\t$MainForm.ClientSize = '793, 295'\r\n\t$MainForm.FormBorderStyle = 'FixedSingle'\r\n\t#region Binary Data\r\n\t$MainForm.Icon = [System.Convert]::FromBase64String('\r\nAAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAA\r\nAIAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAADQAAABUAAAAWAAAAFgAA\r\nABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAA\r\nFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABUAAAANAAAABAAAAA0AAAAr\r\nAAAAPwAAAEMAAABDAAAAQwAAAEMAAABDAAAAQwAAAEMAAABDAAAAQwAAAEMAAABDAAAAQwAAAEMA\r\nAABDAAAAQwAAAEMAAABDAAAAQwAAAEMAAABDAAAAQwAAAEMAAABDAAAAQwAAAEMAAABDAAAAPwAA\r\nACsAAAANAAAAFaZ3FsS3fw//tn0K/7Z8Cf+2fAn/tnwJ/7Z8Cf+2fAn/tnwJ/7Z8Cf+2fAn/tnwJ\r\n/7Z8Cf+2fAn/tnwJ/7Z8Cf+2fAn/tnwJ/7Z8Cf+2fAn/tnwJ/7Z8Cf+2fAn/tnwJ/7Z8Cf+2fAn/\r\ntnwJ/7Z9Cv+3fw//pncWxAAAABUAAAAWt38P//f////z+P//8vf///L3///y9///8vf///L3///y\r\n9///8vf///L3///y9///8vf///L3///y9///8vf///L3///y9///8vf///L3///y9///8vf///L3\r\n///y9///8vf///L3///y9///8/j///f///+3fw//AAAAFgAAABa2fQr/9Pr//+7u8P/t7e3/7e3t\r\n/+3t7f/t7e3/7e3t/+3t7f/t7e3/7e3t/+3t7f/t7e3/7e3t/+3t7f/t7e3/7e3t/+3t7f/t7e3/\r\n7e3t/+3t7f/t7e3/7e3t/+3t7f/t7e3/7e3t/+3t7f/u7vD/9Pr//7Z9Cv8AAAAWAAAAFrZ8Cf/0\r\n+f//6urs/+rp6f/q6en/6unp/+rp6f/q6en/6unp/+rp6f/q6en/6unp/+jn5//o5+f/6Obn/+jm\r\n5//o5uf/6Obn/+jm5//o5uf/6Obn/+jm5//o5uf/6Obn/+jm5//o5+f/6Ofn/+rq7P/0+f//tnwJ\r\n/wAAABYAAAAWtnwJ//T6///o6Or/6Ofn/+no6P/p6Oj/6Ofo/+no6P/p6Oj/6ejo/+jn5//n5ub/\r\n/Pz8///////////////////////////////////////////////////////////////////////8\r\n/Pz/5+fp//T5//+2fAn/AAAAFgAAABa2fAn/9Pr//+jn6P/q6ej/7ezr/+3s6v/r6uj/7Ovq/+3s\r\n6//s6+r/6ejn/+bl5P/w7+//////////////////////////////////////////////////////\r\n//////////////////Du7//m5ub/9Pn//7Z8Cf8AAAAWAAAAFrZ8Cf/0+v//5ubn/+vp6v9OTk7/\r\nkI+P/+3s7P+OjY7/kI+P/46Njf/o5+f/5eTk/+Pk4v//////////////////////////////////\r\n////////////////////////////////////4+Pi/+Tk5v/0+v//tnwJ/wAAABYAAAAWtnwJ//T6\r\n///l4+X/6ufn//Hv7//x7u//7uvs/+3r6//t6+v/7Orq/+fl5f/l4uP/2djV////////////////\r\n///////////////////////////////////////////////////////Y19X/5OLk//T6//+2fAn/\r\nAAAAFgAAABa2fAn/9Pr//+Li4//n5uX/Tk1N/5GQj/+Pjo3/jYyL/+no5/+JiYf/5eTj/+Tj4v/N\r\nzMr//////////////////////////////////////////////////////////////////////83M\r\nyv/i4uP/9fv//7Z8Cf8AAAAWAAAAFrZ8Cf/1+///4N/h/+Lh4v/m5eX/5+bm/+bl5f/l5OT/4+Li\r\n/+Pi4v/i4eH/4uHh/8TCv///////////////////////////////////////////////////////\r\n////////////////xMG//+Hh4//1+///tnwJ/wAAABYAAAAWtnwJ//X7///e3d//393d/+De3v/h\r\n3t7/4N7e/+De3v/g3d7/4N3e/+Dd3f/h39//srKz/7Kysv+wsbH/sLCw/7CwsP+wsLD/sLCw/7Cw\r\nsP+wsLD/sLCw/7CwsP+wsLD/sLGx/7Kysv+ysrL/4N/h//X7//+2fAn/AAAAFgAAABa2fAn/9fv/\r\n/9zc3f/d3Nv/3dzb/93c2//d3Nv/3dzb/93c2//d3Nv/3dzb/97d3P/f3t3/397d/9/e3f/f3t3/\r\n397d/9/e3f/f3t3/397d/9/e3f/f3t3/397d/9/e3f/f3t3/397d/9/e3f/d3N3/9fv//7Z8Cf8A\r\nAAAWAAAAFrZ8Cf/1+///29ra/9za2f/c2tn/3NrZ/9za2f/c2tn/3NrZ/9za2f/c2tn/29nY/9rY\r\n1//Z19b/2dfV/9nX1f/Z19X/2dfV/9nX1f/Z19X/2dfV/9nX1f/Z19X/2dfV/9nX1f/Z19b/2tfW\r\n/9rZ2f/1+///tnwJ/wAAABYAAAAWtnwK//b7///Z2dn/2tnY/9va2f/b2tn/29rZ/9va2f/b2tn/\r\n29rZ/9rZ2P/Y19b//f7+////////////////////////////////////////////////////////\r\n///////////////9/f3/19bX//X7//+2fAr/AAAAFgAAABa2fAr/9vv//9fX1//a2dj/3t3c/97d\r\n3P/d3Nv/29rZ/9zb2v/c29r/2dnY/9bV1P/u7e3/////////////////////////////////////\r\n/////////////////////////////////+3s7P/U1NT/9fv//7Z8Cv8AAAAWAAAAFrZ9Cv/2+///\r\n1tXV/9za2f9JSkj/iYiH/4aFhP/f3Nv/hYSD/4SEgv/a2Nf/1tTS/9/e3v//////////////////\r\n////////////////////////////////////////////////////3t3e/9TS0//2+///tn0K/wAA\r\nABYAAAAWtn0K//b8///U09T/2tjY/+Hf3//i4OD/4N3e/97c3P/f3N3/3dvb/9jW1v/V09P/0tHQ\r\n///////////////////////////////////////////////////////////////////////R0M//\r\n0tHT//b8//+2fQr/AAAAFgAAABa2fQr/9vz//9PS0v/Z19b/SUhI/4iHhv+GhoX/hoWE/4aFhP+D\r\ngoH/19XU/9XT0v/Ew8H/////////////////////////////////////////////////////////\r\n/////////////8PCwP/S0dH/9vz//7Z9Cv8AAAAWAAAAFrZ9Cv/2/P//0M/P/9TS0f/Y1tX/2NbV\r\n/9jW1f/Y1tX/2NXU/9bU0//U0tH/1NHR/7m2tP//////////////////////////////////////\r\n////////////////////////////////uLWz/9HQ0P/3/P//tn0K/wAAABYAAAAWtn0K//b8///N\r\nzc7/0M/O/9DQz//Q0M//0NDP/9DQzv/Qz87/0M/O/9DPzv/S0ND/o6Ok/6Kiov+goaH/oKCg/6Cg\r\noP+goKD/oKCg/6CgoP+goKD/oKCg/6CgoP+goKD/oKGh/6Kiov+io6P/z8/Q//f8//+2fQr/AAAA\r\nFgAAABa2fQr/9vz//8rJy//Mysr/zMrK/8zKyv/Mysr/zMrK/8zKyv/Mysr/zMrK/83Ly//Ozcz/\r\nzs3N/87Nzf/Ozc3/zs3N/87Nzf/Ozc3/zs3N/87Nzf/Ozc3/zs3N/87Nzf/Ozc3/zs3N/83MzP/L\r\nysz/9vz//7Z9Cv8AAAAWAAAAFrZ9DP/0/f//8vf///L4///z+P//8/j///P4///z+P//8/j///P4\r\n///z+P//8/j///P5///z+f//8/n///P5///z+f//8/n///P5///z+f//8/n///P5///z+f//8/n/\r\n//P5///z+f//8/j///L3///0/f//tn0M/wAAABYAAAAWtn8P//rjwv/jq1L/46xV/+OtVv/jrVb/\r\n461W/+OtVv/jrVb/461W/+OtVv/jrVb/461W/+OtVv/jrVb/461W/+OtVv/jrVb/461W/+OtVv/j\r\nrVb/461W/+OtVv/jrVb/461W/+OtVv/jrFX/46tS//rjwv+2fw//AAAAFgAAABa2gBL/9d24/9me\r\nOf/aoT//2qFA/9qhQP/aoUD/2qFA/9qhQP/aoUD/2qFA/9qhQP/aoUD/2qFA/9qhQP/aoUD/2qFA\r\n/9qhQP/aoUD/2qFA/9qhQP/aoUD/2qFA/9qhQP/aoUD/2qFA/9qhP//Znjn/9d24/7aAEv8AAAAW\r\nAAAAFbaBFP/x1qn/0YsX/9KOG//Sjhz/0o4c/9KOHP/Sjhz/0o4c/9KOHP/Sjhz/0o4c/9KOHP/S\r\njhz/0o4c/9KOHP/Sjhz/0o4c/9KOHP/Sjhz/0o4c/9KOHP/Sjhz/0o4c/9KOHP/Sjhz/0o4b/9GL\r\nF//x1qn/toEU/wAAABUAAAANuIIX/+7Pm//szZj/7M6a/+zOmv/szpr/7M6a/+zOmv/szpr/7M6a\r\n/+zOmv/szpr/7M6a/+zOmv/szpr/7M6a/+zOmv/szpr/7M6a/+zOmv/szpr/7M6a/+zOmv/szpr/\r\n7M6a/+zOmv/szpr/7M2Y/+7Pm/+4ghf/AAAADQAAAAS2ghu0uIMX/7eCFv+3gRb/t4EW/7eBFv+3\r\ngRb/t4EW/7eBFv+3gRb/t4EW/7eBFv+3gRb/t4EW/7eBFv+3gRb/t4EW/7eBFv+3gRb/t4EW/7eB\r\nFv+3gRb/t4EW/7eBFv+3gRb/t4EW/7eBFv+3ghb/uIMX/7aCG7QAAAAEAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAP////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAP//////////KAAAABAAAAAgAAAAAQAgAAAAAABABAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAACQAAAAzAAAAMwAAADMAAAAzAAAAMwAAADMAAAAzAAAAMwAAADMAAAAzAAAA\r\nMwAAADMAAAAzAAAAMwAAACSodA3Bt38P/7Z9Cv+2fAr/tnwK/7Z8Cv+2fAr/tnwK/7Z8Cv+2fAr/\r\ntnwK/7Z8Cv+2fAr/tn0K/7d/D/+odA3Bt38P//f////y9///8vb///L2///y9v//8fb///H2///x\r\n9v//8fb///H2///x9v//8fb///L3///3////t38P/7Z9Cv/0+///6+vu/+vq7P/r6+z/6+rs/+rq\r\n7P/p6ev/6Ojq/+fn6f/n5+n/6Ojq/+np6//q6+7/9Pv//7Z9Cv+2fAn/9Pr//+jn5//p6Of/6+ro\r\n/+rp5//o5+b/6+rq///////////////////////r6ur/5ubn//T6//+2fAn/tnwJ//X7///l5Ob/\r\nnZyc/56dnf+dnJz/6OXm/8C/vP//////////////////////v768/+Xj5f/1+///tnwJ/7Z8Cf/1\r\n+///39/h/+Lh4f/k4+P/4+Li/+Pi4v+goKD/oKCg/5+fn/+fn5//oKCg/6CgoP/h4eP/9fv//7Z8\r\nCf+2fAn/9fv//9vb3P/d3Nv/3t3c/97d2//d3Nv/3t3c/93c2v/c29r/3Nva/93c2v/d3Nv/3Nvc\r\n//X7//+2fAn/tnwK//b7///Z2dn/3Nva/93d2//c29r/2tnY/+7t7v//////////////////////\r\n7u3t/9fX2P/2+///tnwK/7Z9Cv/2/P//19XW/5OSkv+VlJX/lJOT/9nX1v/Cwb7/////////////\r\n/////////8HAvf/V1NT/9vz//7Z9Cv+2fQr/9vz//9LR0f/W09L/19XT/9bU0//W09L/oqOj/6Gi\r\nov+goKH/oKCh/6Giov+ioqL/09HS//b8//+2fQr/tn0K//b8///Ky8z/zMzM/8zMzP/MzMz/zczN\r\n/87Ozv/Ozs7/zs7O/87Ozv/Ozs7/zc3N/8vLzf/2/P//tn0K/7Z9DP/1/f//8vf///P3///z9///\r\n8/f///P3///z+P//8/j///P4///z+P//8/j///P3///z9///9f3//7Z9DP+2fxD/9+TA/9yqSv/c\r\nq0r/3KtL/9yrS//cq0v/3KtL/9yrS//cq0v/3KtL/9yrS//cq0r/3KpK//fkwP+2fxD/uIIW/+/S\r\noP/tz5v/7M+b/+zPm//sz5v/7M+b/+zPm//sz5v/7M+b/+zPm//sz5v/7M+b/+3Pm//v0qD/uIIW\r\n/7qFHLK4ghf/t4EU/7aBFP+2gRT/toEU/7aBFP+2gRT/toEU/7aBFP+2gRT/toEU/7aBFP+3gRT/\r\nuIIX/7qFHLIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAA')\r\n\t#endregion\r\n\t$MainForm.Margin = '4, 4, 4, 4'\r\n\t$MainForm.MaximizeBox = $False\r\n\t$MainForm.MinimizeBox = $False\r\n\t$MainForm.Name = 'MainForm'\r\n\t$MainForm.StartPosition = 'CenterScreen'\r\n\t$MainForm.Text = 'Royal TS Dynamic Folder Configurator'\r\n\t$MainForm.add_FormClosing($MainForm_FormClosing)\r\n\t$MainForm.add_Load($MainForm_Load)\r\n\t$MainForm.add_KeyDown($MainForm_KeyDown)\r\n\t$MainForm.add_MouseMove($MainForm_MouseMove)\r\n\t#\r\n\t# checkboxAdminConsole\r\n\t#\r\n\t$checkboxAdminConsole.Location = '379, 113'\r\n\t$checkboxAdminConsole.Name = 'checkboxAdminConsole'\r\n\t$checkboxAdminConsole.Size = '105, 24'\r\n\t$checkboxAdminConsole.TabIndex = 21\r\n\t$checkboxAdminConsole.Text = 'Admin/Console'\r\n\t$infoToolTip.SetToolTip($checkboxAdminConsole, 'Selecting this checkbox will set the Remote Desktop Connection\r\n to be an Admin/Console connection')\r\n\t$checkboxAdminConsole.UseCompatibleTextRendering = $True\r\n\t$checkboxAdminConsole.UseVisualStyleBackColor = $True\r\n\t$checkboxAdminConsole.Visible = $False\r\n\t#\r\n\t# OUNameButton\r\n\t#\r\n\t$OUNameButton.Enabled = $False\r\n\t$OUNameButton.Location = '748, 170'\r\n\t$OUNameButton.Name = 'OUNameButton'\r\n\t$OUNameButton.Size = '37, 23'\r\n\t$OUNameButton.TabIndex = 20\r\n\t$OUNameButton.Text = '...'\r\n\t$infoToolTip.SetToolTip($OUNameButton, 'Click this button to bring up a GUI to select the OU to search for computer accounts in')\r\n\t$OUNameButton.UseCompatibleTextRendering = $True\r\n\t$OUNameButton.UseVisualStyleBackColor = $True\r\n\t$OUNameButton.add_Click($OUNameButton_Click)\r\n\t#\r\n\t# checkboxUseCim\r\n\t#\r\n\t$checkboxUseCim.Location = '269, 113'\r\n\t$checkboxUseCim.Name = 'checkboxUseCim'\r\n\t$checkboxUseCim.Size = '104, 24'\r\n\t$checkboxUseCim.TabIndex = 3\r\n\t$checkboxUseCim.Text = 'Use Cim'\r\n\t$infoToolTip.SetToolTip($checkboxUseCim, 'For connection types that can use CIM session, checking this box enables the use of CIM connections.')\r\n\t$checkboxUseCim.UseCompatibleTextRendering = $True\r\n\t$checkboxUseCim.UseVisualStyleBackColor = $True\r\n\t$checkboxUseCim.Visible = $False\r\n\t#\r\n\t# portNumberTextBox\r\n\t#\r\n\t$portNumberTextBox.ForeColor = 'Black'\r\n\t$portNumberTextBox.Location = '105, 115'\r\n\t$portNumberTextBox.Name = 'portNumberTextBox'\r\n\t$portNumberTextBox.Size = '120, 20'\r\n\t$portNumberTextBox.TabIndex = 2\r\n\t$infoToolTip.SetToolTip($portNumberTextBox, 'Enter the port number for the connection. The default value is loaded on connection type change.')\r\n\t#\r\n\t# labelPortNumber\r\n\t#\r\n\t$labelPortNumber.AutoSize = $True\r\n\t$labelPortNumber.Location = '13, 118'\r\n\t$labelPortNumber.Name = 'labelPortNumber'\r\n\t$labelPortNumber.Size = '68, 17'\r\n\t$labelPortNumber.TabIndex = 19\r\n\t$labelPortNumber.Text = 'Port Number'\r\n\t$labelPortNumber.UseCompatibleTextRendering = $True\r\n\t#\r\n\t# labelConnectionType\r\n\t#\r\n\t$labelConnectionType.AutoSize = $True\r\n\t$labelConnectionType.Location = '12, 88'\r\n\t$labelConnectionType.Name = 'labelConnectionType'\r\n\t$labelConnectionType.Size = '90, 17'\r\n\t$labelConnectionType.TabIndex = 16\r\n\t$labelConnectionType.Text = 'Connection Type'\r\n\t$labelConnectionType.UseCompatibleTextRendering = $True\r\n\t#\r\n\t# connectionTypeDropDown\r\n\t#\r\n\t$connectionTypeDropDown.DropDownStyle = 'DropDownList'\r\n\t$connectionTypeDropDown.FlatStyle = 'Popup'\r\n\t$connectionTypeDropDown.FormattingEnabled = $True\r\n\t[void]$connectionTypeDropDown.Items.Add('SecureGateway')\r\n\t[void]$connectionTypeDropDown.Items.Add('RoyalServer')\r\n\t[void]$connectionTypeDropDown.Items.Add('RemoteDesktopGateway')\r\n\t[void]$connectionTypeDropDown.Items.Add('RemoteDesktopConnection')\r\n\t[void]$connectionTypeDropDown.Items.Add('TerminalConnection - SSH')\r\n\t[void]$connectionTypeDropDown.Items.Add('TerminalConnection - Telnet')\r\n\t[void]$connectionTypeDropDown.Items.Add('TerminalConnection - Serial')\r\n\t[void]$connectionTypeDropDown.Items.Add('VNCConnection')\r\n\t[void]$connectionTypeDropDown.Items.Add('WindowsEventsConnection')\r\n\t[void]$connectionTypeDropDown.Items.Add('WindowsServicesConnection')\r\n\t[void]$connectionTypeDropDown.Items.Add('WindowsProcessesConnection')\r\n\t[void]$connectionTypeDropDown.Items.Add('TerminalServicesConnection')\r\n\t[void]$connectionTypeDropDown.Items.Add('PowerShellConnection')\r\n\t$connectionTypeDropDown.Location = '104, 85'\r\n\t$connectionTypeDropDown.Name = 'connectionTypeDropDown'\r\n\t$connectionTypeDropDown.Size = '168, 21'\r\n\t$connectionTypeDropDown.TabIndex = 1\r\n\t$infoToolTip.SetToolTip($connectionTypeDropDown, 'Select the connection type to create.')\r\n\t$connectionTypeDropDown.add_SelectedIndexChanged($connectionTypeDropDown_SelectedIndexChanged)\r\n\t#\r\n\t# credentialTextBox\r\n\t#\r\n\t$credentialTextBox.ForeColor = 'Black'\r\n\t$credentialTextBox.Location = '104, 144'\r\n\t$credentialTextBox.Name = 'credentialTextBox'\r\n\t$credentialTextBox.Size = '268, 20'\r\n\t$credentialTextBox.TabIndex = 4\r\n\t$infoToolTip.SetToolTip($credentialTextBox, 'The name of the RoyalTS credential name to assign to the connection.\r\nIf this field is left blank, then the connections (and folders) will\r\nbe set to inherit the credentials from the Dynamic Folder settings.')\r\n\t#\r\n\t# labelCredentialName\r\n\t#\r\n\t$labelCredentialName.AutoSize = $True\r\n\t$labelCredentialName.Location = '12, 147'\r\n\t$labelCredentialName.Name = 'labelCredentialName'\r\n\t$labelCredentialName.Size = '89, 17'\r\n\t$labelCredentialName.TabIndex = 15\r\n\t$labelCredentialName.Text = 'Credential Name'\r\n\t$labelCredentialName.UseCompatibleTextRendering = $True\r\n\t#\r\n\t# labelPDC\r\n\t#\r\n\t$labelPDC.AutoSize = $True\r\n\t$labelPDC.Location = '12, 62'\r\n\t$labelPDC.Name = 'labelPDC'\r\n\t$labelPDC.Size = '28, 17'\r\n\t$labelPDC.TabIndex = 13\r\n\t$labelPDC.Text = 'PDC'\r\n\t$labelPDC.UseCompatibleTextRendering = $True\r\n\t#\r\n\t# dcTextBox\r\n\t#\r\n\t$dcTextBox.ForeColor = 'LightGray'\r\n\t$dcTextBox.Location = '104, 59'\r\n\t$dcTextBox.Name = 'dcTextBox'\r\n\t$dcTextBox.ReadOnly = $True\r\n\t$dcTextBox.Size = '269, 20'\r\n\t$dcTextBox.TabIndex = 12\r\n\t$dcTextBox.TabStop = $False\r\n\t#\r\n\t# buttonSubmit\r\n\t#\r\n\t$buttonSubmit.Location = '710, 265'\r\n\t$buttonSubmit.Name = 'buttonSubmit'\r\n\t$buttonSubmit.Size = '75, 23'\r\n\t$buttonSubmit.TabIndex = 8\r\n\t$buttonSubmit.Text = '&Submit'\r\n\t$buttonSubmit.UseCompatibleTextRendering = $True\r\n\t$buttonSubmit.UseVisualStyleBackColor = $True\r\n\t$buttonSubmit.add_Click($buttonSubmit_Click)\r\n\t#\r\n\t# domainTextBox\r\n\t#\r\n\t$domainTextBox.ForeColor = 'Black'\r\n\t$domainTextBox.Location = '105, 6'\r\n\t$domainTextBox.Name = 'domainTextBox'\r\n\t$domainTextBox.Size = '268, 20'\r\n\t$domainTextBox.TabIndex = 0\r\n\t$infoToolTip.SetToolTip($domainTextBox, 'Enter in the name of the domain to query')\r\n\t$domainTextBox.add_KeyDown($domainTextBox_KeyDown)\r\n\t$domainTextBox.add_Leave($domainTextBox_Leave)\r\n\t#\r\n\t# labelDCRoot\r\n\t#\r\n\t$labelDCRoot.AutoSize = $True\r\n\t$labelDCRoot.Location = '12, 36'\r\n\t$labelDCRoot.Name = 'labelDCRoot'\r\n\t$labelDCRoot.Size = '47, 17'\r\n\t$labelDCRoot.TabIndex = 10\r\n\t$labelDCRoot.Text = 'DC Root'\r\n\t$labelDCRoot.UseCompatibleTextRendering = $True\r\n\t#\r\n\t# dcRootTextBox\r\n\t#\r\n\t$dcRootTextBox.ForeColor = 'LightGray'\r\n\t$dcRootTextBox.Location = '104, 33'\r\n\t$dcRootTextBox.Name = 'dcRootTextBox'\r\n\t$dcRootTextBox.ReadOnly = $True\r\n\t$dcRootTextBox.Size = '269, 20'\r\n\t$dcRootTextBox.TabIndex = 9\r\n\t$dcRootTextBox.TabStop = $False\r\n\t$dcRootTextBox.add_TextChanged($dcRootTextBox_TextChanged)\r\n\t#\r\n\t# labelDomainName\r\n\t#\r\n\t$labelDomainName.AutoSize = $True\r\n\t$labelDomainName.Location = '12, 9'\r\n\t$labelDomainName.Name = 'labelDomainName'\r\n\t$labelDomainName.Size = '76, 17'\r\n\t$labelDomainName.TabIndex = 8\r\n\t$labelDomainName.Text = 'Domain Name'\r\n\t$labelDomainName.UseCompatibleTextRendering = $True\r\n\t#\r\n\t# searchBaseTextBox\r\n\t#\r\n\t$searchBaseTextBox.ForeColor = 'Black'\r\n\t$searchBaseTextBox.Location = '104, 172'\r\n\t$searchBaseTextBox.Name = 'searchBaseTextBox'\r\n\t$searchBaseTextBox.ReadOnly = $True\r\n\t$searchBaseTextBox.Size = '633, 20'\r\n\t$searchBaseTextBox.TabIndex = 5\r\n\t$infoToolTip.SetToolTip($searchBaseTextBox, 'The OU to search under for the computers to connect to')\r\n\t$searchBaseTextBox.add_KeyDown($searchBaseTextBox_KeyDown)\r\n\t#\r\n\t# filterTextBox\r\n\t#\r\n\t$filterTextBox.ForeColor = 'Black'\r\n\t$filterTextBox.Location = '104, 230'\r\n\t$filterTextBox.Name = 'filterTextBox'\r\n\t$filterTextBox.Size = '681, 20'\r\n\t$filterTextBox.TabIndex = 7\r\n\t$filterTextBox.Text = '*'\r\n\t$infoToolTip.SetToolTip($filterTextBox, 'Enter in the ActiveDirectory Module filter. Default is *\r\nExample: name -like ''test*''')\r\n\t$filterTextBox.add_KeyDown($filterTextBox_KeyDown)\r\n\t#\r\n\t# labelFilter\r\n\t#\r\n\t$labelFilter.AutoSize = $True\r\n\t$labelFilter.Location = '13, 233'\r\n\t$labelFilter.Name = 'labelFilter'\r\n\t$labelFilter.Size = '29, 17'\r\n\t$labelFilter.TabIndex = 5\r\n\t$labelFilter.Text = 'Filter'\r\n\t$labelFilter.UseCompatibleTextRendering = $True\r\n\t#\r\n\t# labelSearchScope\r\n\t#\r\n\t$labelSearchScope.AutoSize = $True\r\n\t$labelSearchScope.Location = '13, 205'\r\n\t$labelSearchScope.Name = 'labelSearchScope'\r\n\t$labelSearchScope.Size = '72, 17'\r\n\t$labelSearchScope.TabIndex = 3\r\n\t$labelSearchScope.Text = 'SearchScope'\r\n\t$labelSearchScope.UseCompatibleTextRendering = $True\r\n\t#\r\n\t# scopeComboBox\r\n\t#\r\n\t$scopeComboBox.DropDownStyle = 'DropDownList'\r\n\t$scopeComboBox.FlatStyle = 'Popup'\r\n\t$scopeComboBox.FormattingEnabled = $True\r\n\t[void]$scopeComboBox.Items.Add('Base')\r\n\t[void]$scopeComboBox.Items.Add('OneLevel')\r\n\t[void]$scopeComboBox.Items.Add('Subtree')\r\n\t$scopeComboBox.Location = '104, 202'\r\n\t$scopeComboBox.Name = 'scopeComboBox'\r\n\t$scopeComboBox.Size = '121, 21'\r\n\t$scopeComboBox.TabIndex = 6\r\n\t$infoToolTip.SetToolTip($scopeComboBox, 'Select the search scope of the comptuer objects to find. Default value is SubTree.\r\nSubtree searches recursivly under the selected OU for all comptuers.\r\nBase searches only in the selected OU.\r\nOneLevel searches only in the OUs directly under the selected OU.')\r\n\t$scopeComboBox.add_KeyDown($scopeComboBox_KeyDown)\r\n\t#\r\n\t# labelSearchBase\r\n\t#\r\n\t$labelSearchBase.AutoSize = $True\r\n\t$labelSearchBase.Location = '12, 175'\r\n\t$labelSearchBase.Name = 'labelSearchBase'\r\n\t$labelSearchBase.Size = '66, 17'\r\n\t$labelSearchBase.TabIndex = 0\r\n\t$labelSearchBase.Text = 'SearchBase'\r\n\t$infoToolTip.SetToolTip($labelSearchBase, 'The OU to search under for the computers to connect to')\r\n\t$labelSearchBase.UseCompatibleTextRendering = $True\r\n\t#\r\n\t# keepSettingTimer\r\n\t#\r\n\t$keepSettingTimer.Interval = 5000\r\n\t$keepSettingTimer.add_Tick($keepSettingTimer_Tick)\r\n\t#\r\n\t# infoToolTip\r\n\t#\r\n\t$infoToolTip.AutomaticDelay = 100\r\n\t$infoToolTip.AutoPopDelay = 30000\r\n\t$infoToolTip.InitialDelay = 100\r\n\t$infoToolTip.IsBalloon = $True\r\n\t$infoToolTip.ReshowDelay = 20\r\n\t$infoToolTip.ToolTipIcon = 'Info'\r\n\t$infoToolTip.ToolTipTitle = 'Information'\r\n\t$MainForm.ResumeLayout()\r\n\t#endregion Generated Form Code\r\n\r\n\t#----------------------------------------------\r\n\r\n\t#Save the initial state of the form\r\n\t$InitialFormWindowState = $MainForm.WindowState\r\n\t#Init the OnLoad event to correct the initial state of the form\r\n\t$MainForm.add_Load($Form_StateCorrection_Load)\r\n\t#Clean up the control events\r\n\t$MainForm.add_FormClosed($Form_Cleanup_FormClosed)\r\n\t#Store the control values when form is closing\r\n\t$MainForm.add_Closing($Form_StoreValues_Closing)\r\n\t#Show the Form\r\n\treturn $MainForm.ShowDialog()\r\n\r\n}\r\n#endregion Source: MainForm.psf\r\n\r\n#region Source: OU Selector.psf\r\nfunction Show-OU_Selector_psf\r\n{\r\n#region File Recovery Data (DO NOT MODIFY)\r\n<#RecoveryData:\r\n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#>\r\n#endregion\r\n\t#----------------------------------------------\r\n\t#region Import the Assemblies\r\n\t#----------------------------------------------\r\n\t[void][reflection.assembly]::Load('System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')\r\n\t[void][reflection.assembly]::Load('System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')\r\n\t#endregion Import Assemblies\r\n\r\n\t#----------------------------------------------\r\n\t#region Generated Form Objects\r\n\t#----------------------------------------------\r\n\t[System.Windows.Forms.Application]::EnableVisualStyles()\r\n\t$formOUSelection = New-Object 'System.Windows.Forms.Form'\r\n\t$checkboxUseDomainRootInstead = New-Object 'System.Windows.Forms.CheckBox'\r\n\t$treeview1 = New-Object 'System.Windows.Forms.TreeView'\r\n\t$buttonOk = New-Object 'System.Windows.Forms.Button'\r\n\t$imagelistLargeImages = New-Object 'System.Windows.Forms.ImageList'\r\n\t$imagelistSmallImages = New-Object 'System.Windows.Forms.ImageList'\r\n\t$InitialFormWindowState = New-Object 'System.Windows.Forms.FormWindowState'\r\n\t#endregion Generated Form Objects\r\n\r\n\t#----------------------------------------------\r\n\t# User Generated Script\r\n\t#----------------------------------------------\r\n\tfunction Get-AHCLdapOU\r\n\t{\r\n\t\t[CmdletBinding()]\r\n\t\tparam\r\n\t\t(\r\n\t\t\t[Parameter(Mandatory = $true)]\r\n\t\t\t[string]$OUPath\r\n\t\t)\r\n\t\t\r\n\t\t$strFilter = \"(objectCategory=organizationalunit)\"\r\n\t\t$objDomain = New-Object System.DirectoryServices.DirectoryEntry (\"LDAP://$($OUPath)\")\r\n\t\t$objSearcher = New-Object System.DirectoryServices.DirectorySearcher\r\n\t\t$objSearcher.SearchRoot = $objDomain\r\n\t\t$objSearcher.PageSize = 1000\r\n\t\t$objSearcher.Filter = $strFilter\r\n\t\t$objSearcher.SearchScope = \"OneLevel\"\r\n\t\t$counter = 0\r\n\t\tdo\r\n\t\t{\r\n\t\t\t$counter++\r\n\t\t\t$colResults = $objSearcher.FindAll()\r\n\t\t\t$userFound = $?\r\n\t\t}\r\n\t\twhile ($userFound -eq $false -and $counter -le 30)\r\n\t\treturn $colResults\r\n\t}\r\n\t\r\n\tfunction Get-AHCOUTree\r\n\t{\r\n\t\t[CmdletBinding()]\r\n\t\tparam\r\n\t\t(\r\n\t\t\t[int]$MaxLength\r\n\t\t)\r\n\t\t$treeview1.nodes.clear()\r\n\t\t\r\n\t\t$domainDN = New-Object System.DirectoryServices.DirectoryEntry(\"LDAP://$($script:selectedDomainRoot)\")\r\n\t\t\r\n\t\t$ouList = Get-AHCLdapOU -OUPath \"$($domainDN.distinguishedname)\"\r\n\t\t$script:siteArray = New-Object System.Collections.Generic.list[object]\r\n\t\t\r\n\t\tforeach ($item in $oulist.path)\r\n\t\t{\r\n\t\t\t[System.Windows.Forms.application]::DoEvents\t\t\r\n\t\t\t$ouname = (($item.replace(\"LDAP://\", \"\") -split \",\")[0].replace(\"OU=\", \"\"))\r\n\t\t\t$oupath = $item.replace(\"LDAP://\", \"\")\r\n\t\t\t$subobjectarray = New-Object System.Collections.Generic.list[object]\r\n\t\t\t$script:array = New-Object System.Collections.Generic.list[object]\r\n\t\t\t$obj = New-Object System.Windows.Forms.treenode(\"$($ouname)\", [System.Windows.Forms.TreeNode[]]($subObjectArray))\r\n\t\t\t$obj.name = $oupath\r\n\t\t\t$obj.text = \"$($ouname)\"\r\n\t\t\t$treeview1.Nodes.add($obj)\r\n\t\t}\r\n\t}\r\n\t\r\n\tfunction get-resultingOU\r\n\t{\r\n\t\tif ($checkboxUseDomainRootInstead.CheckState -eq 'Checked')\r\n\t\t{\r\n\t\t\t$script:selectedOU = $script:selectedDomainRoot.trim()\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t$script:selectedOU = $treeview1.SelectedNode.Name.tostring()\r\n\t\t}\r\n\t}\r\n\t\r\n\t$formOUSelection_Load={\r\n\t\t$treeview1.Nodes.clear()\r\n\t\tGet-AHCOUTree\r\n\t\t$preReverse = [System.Collections.arraylist]@()\r\n\t\t$ous = $script:currentlySelectedOU.split(\",\") | Where-Object { $_ -like \"OU=*\" }\r\n\t\t$dcs = $script:currentlySelectedOU.split(\",\") | Where-Object { $_ -like \"DC=*\" }\r\n\t\t$dccombined = $dcs -join \",\"\r\n\t\t$counter = 0\r\n\t\t$maxnumber = ($ous | Measure-Object).count - 1\r\n\t\tforeach ($item in $ous)\r\n\t\t{\r\n\t\t\t$templist = $ous[$counter .. $maxnumber] -join \",\"\r\n\t\t\t$preReverse.add(\"$($templist),$($dccombined)\") | Out-Null\r\n\t\t\t$counter ++\r\n\t\t}\r\n\t\t$preReverse.Reverse()\r\n\t\tforeach ($item in $preReverse)\r\n\t\t{\r\n\t\t\t$nodeSelection = $treeview1.Nodes.find($item, $true)\r\n\t\t\t$treeview1.SelectedNode = [System.Windows.Forms.treenode]$nodeselection[0]\r\n\t\t\t$treeview1.select()\r\n\t\t\t$treeview1.focus()\r\n\t\t}\r\n\t}\r\n\t\r\n\tfunction Get-CheckedNode\r\n\t{\r\n\t<#\r\n\t\t.SYNOPSIS\r\n\t\t\tThis function collects a list of checked nodes in a TreeView\r\n\t\r\n\t\t.DESCRIPTION\r\n\t\t\tThis function collects a list of checked nodes in a TreeView\r\n\t\r\n\t\t.PARAMETER $NodeCollection\r\n\t\t\tThe collection of nodes to search\r\n\t\r\n\t\t.PARAMETER $CheckedNodes\r\n\t\t\tThe ArrayList that will contain the all the checked items\r\n\t\t\r\n\t\t.EXAMPLE\r\n\t\t\t$CheckedNodes = New-Object System.Collections.ArrayList\r\n\t\t\tGet-CheckedNode $treeview1.Nodes $CheckedNodes\r\n\t\t\tforeach($node in $CheckedNodes)\r\n\t\t\t{\t\r\n\t\t\t\tWrite-Host $node.Text\r\n\t\t\t}\r\n\t#>\r\n\t\tparam (\r\n\t\t\t\t[ValidateNotNull()]\r\n\t\t\t\t[System.Windows.Forms.TreeNodeCollection]$NodeCollection,\r\n\t\t\t\t[ValidateNotNull()]\r\n\t\t\t\t[System.Collections.ArrayList]$CheckedNodes\r\n\t\t)\r\n\t\t\r\n\t\tforeach ($Node in $NodeCollection)\r\n\t\t{\r\n\t\t\tif ($Node.Checked)\r\n\t\t\t{\r\n\t\t\t\t[void]$CheckedNodes.Add($Node)\r\n\t\t\t}\r\n\t\t\tGet-CheckedNode $Node.Nodes $CheckedNodes\r\n\t\t}\r\n\t}\r\n\t\r\n\t$treeview1_AfterSelect=[System.Windows.Forms.TreeViewEventHandler]{\r\n\t\t\r\n\t\t[System.Windows.Forms.application]::DoEvents\r\n\t\t$selectednode = $treeview1.SelectedNode.Name.tostring()\r\n\t\t$treeview1.SelectedNode.Nodes.clear()\r\n\t\tforeach ($item in Get-AHCLdapOU -OUPath $selectednode)\r\n\t\t{\r\n\t\t\t$obj2 = New-Object System.Windows.Forms.treenode(\"$($item.properties.name)\")\r\n\t\t\t$obj2.name = $($item.properties.distinguishedname)\r\n\t\t\t$obj2.text = $($item.properties.name)\r\n\t\t\t$treeview1.SelectedNode.Nodes.add($obj2)\r\n\t\t}\r\n\t\t\r\n\t}\r\n\t\r\n\t$buttonOk_Click={\r\n\t\tget-resultingOU\r\n\t}\r\n\t\r\n\t$formOUSelection_FormClosing=[System.Windows.Forms.FormClosingEventHandler]{\r\n\t\tget-resultingOU\r\n\t}\r\n\t# --End User Generated Script--\r\n\t#----------------------------------------------\r\n\t#region Generated Events\r\n\t#----------------------------------------------\r\n\t\r\n\t$Form_StateCorrection_Load=\r\n\t{\r\n\t\t#Correct the initial state of the form to prevent the .Net maximized form issue\r\n\t\t$formOUSelection.WindowState = $InitialFormWindowState\r\n\t}\r\n\t\r\n\t$Form_StoreValues_Closing=\r\n\t{\r\n\t\t#Store the control values\r\n\t\t$script:OU_Selector_checkboxUseDomainRootInstead = $checkboxUseDomainRootInstead.Checked\r\n\t\tif($treeview1.SelectedNode -ne $null)\r\n\t\t{\r\n\t\t\t$script:OU_Selector_treeview1 = $treeview1.SelectedNode.Text\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t$script:OU_Selector_treeview1 = $null\r\n\t\t}\r\n\t}\r\n\r\n\t\r\n\t$Form_Cleanup_FormClosed=\r\n\t{\r\n\t\t#Remove all event handlers from the controls\r\n\t\ttry\r\n\t\t{\r\n\t\t\t$treeview1.remove_AfterSelect($treeview1_AfterSelect)\r\n\t\t\t$buttonOk.remove_Click($buttonOk_Click)\r\n\t\t\t$formOUSelection.remove_FormClosing($formOUSelection_FormClosing)\r\n\t\t\t$formOUSelection.remove_Load($formOUSelection_Load)\r\n\t\t\t$formOUSelection.remove_Load($Form_StateCorrection_Load)\r\n\t\t\t$formOUSelection.remove_Closing($Form_StoreValues_Closing)\r\n\t\t\t$formOUSelection.remove_FormClosed($Form_Cleanup_FormClosed)\r\n\t\t}\r\n\t\tcatch { Out-Null <# Prevent PSScriptAnalyzer warning #> }\r\n\t}\r\n\t#endregion Generated Events\r\n\r\n\t#----------------------------------------------\r\n\t#region Generated Form Code\r\n\t#----------------------------------------------\r\n\t$formOUSelection.SuspendLayout()\r\n\t#\r\n\t# formOUSelection\r\n\t#\r\n\t$formOUSelection.Controls.Add($checkboxUseDomainRootInstead)\r\n\t$formOUSelection.Controls.Add($treeview1)\r\n\t$formOUSelection.Controls.Add($buttonOk)\r\n\t$formOUSelection.AcceptButton = $buttonOk\r\n\t$formOUSelection.AutoScaleDimensions = '6, 13'\r\n\t$formOUSelection.AutoScaleMode = 'Font'\r\n\t$formOUSelection.ClientSize = '640, 392'\r\n\t$formOUSelection.FormBorderStyle = 'FixedSingle'\r\n\t#region Binary Data\r\n\t$formOUSelection.Icon = [System.Convert]::FromBase64String('\r\nAAABAAcAQEAAAAEAIAAoQgAAdgAAADAwAAABACAAqCUAAJ5CAAAoKAAAAQAgAGgaAABGaAAAICAA\r\nAAEAIACoEAAAroIAABgYAAABACAAiAkAAFaTAAAUFAAAAQAgALgGAADenAAAEBAAAAEAIABoBAAA\r\nlqMAACgAAABAAAAAgAAAAAEAIAAAAAAAAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eAJ4eHgZeHh4GXh4eBl4eHgZeHh4GXh4eBl4eHgCAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH19ff2AgID/gICA\r\n/4CAgP+AgID/gICA/4CAgP+AgID/gICA/319ff0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PvOzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAACAgID/fX19/4CAgP+AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/\r\neHh4AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACz\r\neD7zs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\nBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4eHgEgICA/4CAgP//////\r\n//////////////////////////96enr/gICA/3Z2dhMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+87N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAeHh4BICAgP+AgID/////////////////////////////////gICA/4CAgP9z\r\nc3MTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4\r\nPvOzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4H\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eASAgID/gICA////////\r\n/////////////////////////4CAgP+AgID/aWlp/2hoaP9oaGj/aGho/2hoaP9oaGj/aGho/2ho\r\naP9oaGj/aGho/2hoaP9oaGj/aGho/2hoaP+vdz//s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAB4eHgEgICA/4CAgP////////////////////////////////+AgID/gICA/2lp\r\naf9oaGj/aGho/2hoaP9oaGj/aGho/2hoaP9oaGj/aGho/2hoaP9oaGj/aGho/2hoaP9oaGj/r3c/\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgcA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeHh4BICAgP+AgID/////////\r\n////////////////////////gICA/4CAgP9zc3MTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PvOzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAHh4eAOAgID/gICA//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4/4CAgP+AgID/dXV1\r\nEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7z\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+BwAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA/319ff+AgID/gICA\r\n/4CAgP+AgID/gICA/4CAgP+AgID/gICA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+87N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAH19ffyAgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/319ffwAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PvOz\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4HAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nZmZm/GZmZv4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4\r\nPgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+\r\nDLN4PgyzeD4Ms3g+DLN4PgyzeD4MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZmZv9mZmb/AAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABm\r\nZmb/ZmZm/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZmZm/2ZmZv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eAJ1dXUZcnJyGWZm\r\nZvxmZmb+cnJyGXR0dBl4eHgCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAH19ff2AgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/319ff0AAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PvOzeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4HAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgID/fX19/4CAgP+AgID/gICA\r\n/4CAgP+AgID/gICA/319ff+AgID/eHh4AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7zs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAB4eHgEgICA/4CAgP////////////////////////////////+AgID/gICA/3Z2dhMAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+87N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgcAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeHh4BICAgP+AgID/////////////////\r\n////////////////gICA/4CAgP9zc3MTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAALN4PvOzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD4HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAHh4eASAgID/gICA/////////////////////////////////4CAgP+AgID/aWlp/2hoaP9o\r\naGj/aGho/2hoaP9oaGj/aGho/2hoaP9oaGj/aGho/2hoaP9oaGj/aGho/2hoaP+vdz//s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+BwAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4eHgEgICA/4CAgP//////////////////\r\n//////////////+AgID/gICA/2lpaf9oaGj/aGho/2hoaP9oaGj/aGho/2hoaP9oaGj/aGho/2ho\r\naP9oaGj/aGho/2hoaP9oaGj/r3c//7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4PgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAeHh4BICAgP+AgID/////////////////////////////////gICA/4CAgP9zc3MTAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PvOzeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4HAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eAOAgID/gICA//j4+P/4+Pj/+Pj4//j4\r\n+P/4+Pj/+Pj4/4CAgP+AgID/dXV1EgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAACzeD7zs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAgICA/319ff+AgID/gICA/4CAgP+AgID/gICA/4CAgP99fX3/gICA/wAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+87N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgcAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH19ffyAgID/gICA/4CAgP+AgID/gICA\r\n/4CAgP+AgID/gICA/319ffwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAALN4PvOzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD4HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAZmZm/GZmZv4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD4Ms3g+DLN4Pgyz\r\neD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4\r\nPgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4MAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZmZv9mZmb/\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAABmZmb/ZmZm/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZmZm/2ZmZv8A\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAGZmZvxmZmb+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH19ff2AgID/gICA/4CAgP+AgID/gICA/4CA\r\ngP+AgID/gICA/319ff0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAALN4Pv6zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD4HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAACAgID/fX19/4CAgP+AgID/gICA/4CAgP+AgID/gICA/319ff+AgID/eHh4AQAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7+s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+BwAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4eHgEgICA/4CAgP//////////////////////////\r\n//////+AgID/gICA/3Z2dhMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAs3g+/rN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4PgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeHh4\r\nBICAgP+AgID/////////////////////////////////gICA/4CAgP9zc3MTAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4Pv6zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4HAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eASAgID/gICA////////////////////////////\r\n/////4CAgP+AgID/aWlp/2hoaP9oaGj/aGho/2hoaP9oaGj/aGho/2hoaP9oaGj/aGho/2hoaP9o\r\naGj/aGho/2hoaP+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4eHgE\r\ngICA/4CAgP////////////////////////////////+AgID/gICA/2lpaf9oaGj/aGho/2hoaP9o\r\naGj/aGho/2hoaP9oaGj/aGho/2hoaP9oaGj/aGho/2hoaP9oaGj/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgcAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeHh4BICAgP+AgID/////////////////////////////\r\n////gICA/4CAgP9zc3MTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAALN4Pv6zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD4HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eAOA\r\ngID/gICA//j4+P/4+Pj/+Pj4//j4+P/4+Pj/+Pj4/4CAgP+AgID/dXV1EgAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7+s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+BwAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA/319ff+AgID/gICA/4CAgP+AgID/gICA/4CA\r\ngP99fX3/gICA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAs3g+/rN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4PgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH19\r\nffyAgID/gICA/4CAgP+AgID/gICA/4CAgP+AgID/gICA/319ffwAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4Pv6zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4HAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZmZm/GZmZv4AAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAACzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4Pgyz\r\neD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4\r\nPgyzeD4MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAGZmZv9mZmb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmZmb/ZmZm/wAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAZmZm/2ZmZv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZmZv9mZmb/AAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAABmZmb/ZmZm/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZmZm/GZmZv4AAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7zs3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+BwAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAs3g+87N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4PgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PvOzeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4HAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAACzeD7zs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+87N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAALN4PvOzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD4HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7zs3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAs3g+87N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4PgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PvOzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAACzeD7zs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+\r\nDLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4M\r\ns3g+DLN4PgyzeD4Ms3g+DLN4PgyzeD4Ms3g+DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAA//////////////////////+Af////////wA//wAAAAf/AB//AAAAB/4AH/8A\r\nAAAH/gAf/wAAAAf+AAAAAAAAB/4AAAAAAAAH/gAf/wAAAAf+AB//AAAAB/8AP/8AAAAH/wA//wAA\r\nAAf/8///AAAAD//z//////////P/////////8/////////+Af////////wA//wAAAAf/AB//AAAA\r\nB/4AH/8AAAAH/gAf/wAAAAf+AAAAAAAAB/4AAAAAAAAH/gAf/wAAAAf+AB//AAAAB/8AP/8AAAAH\r\n/wA//wAAAAf/8///AAAAD//z//////////P/////////8//////////z/////////wA//wAAAAf/\r\nAB//AAAAB/4AH/8AAAAH/gAf/wAAAAf+AAAAAAAAB/4AAAAAAAAH/gAf/wAAAAf+AB//AAAAB/8A\r\nP/8AAAAH/wA//wAAAAf/8///AAAAD//z//////////P/////////8//////////z//////////P/\r\n////////8/////////AAAAB/////8AAAAH/////wAAAAf/////AAAAB/////8AAAAH/////wAAAA\r\nf/////AAAAB/////8AAAAH/////wAAAAf/////AAAAB/////8AAAAP//////////////////////\r\n//////////////8oAAAAMAAAAGAAAAABACAAAAAAAIAlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9\r\nfX39gICA/4CAgP+AgID/gICA/4CAgP+AgID/fX19/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAHh4eAGAgID/fX19/4CAgP+AgID/gICA/4CAgP99fX3/gICA/wAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eBaAgID/gICA////////////\r\n//////f39/+AgID/gICA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAHh4eBaAgID/gICA//////////////////f39/+AgID/gICA/2hoaP9mZmb/ZmZm/2ZmZv9mZmb/\r\nZmZm/2ZmZv9oaGj/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eBaAgID/gICA//////////////////f39/+AgID/gICA\r\n/2hoaP9mZmb/ZmZm/2ZmZv9mZmb/ZmZm/2ZmZv9oaGj/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eBaAgID/gICA////\r\n//////////////f39/+AgID/gICA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAHh4eAGAgID/fX19/4CAgP+AgID/gICA/4CAgP99fX3/gICA/wAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9fX39gICA/4CAgP+AgID/gICA/4CAgP+A\r\ngID/fX19/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAABoaGj/aGho/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmZmb/ZmZm/wAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoaGj/aGho\r\n/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAB9fX39gICA/4CAgP+AgID/gICA/4CAgP+AgID/fX19/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAHh4eAGAgID/fX19/4CAgP+AgID/gICA/4CAgP99fX3/gICA/wAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eBaAgID/gICA////////\r\n//////////f39/+AgID/gICA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAHh4eBaAgID/gICA//////////////////f39/+AgID/gICA/2hoaP9mZmb/ZmZm/2ZmZv9m\r\nZmb/ZmZm/2ZmZv9oaGj/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eBaAgID/gICA//////////////////f39/+AgID/\r\ngICA/2hoaP9mZmb/ZmZm/2ZmZv9mZmb/ZmZm/2ZmZv9oaGj/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eBaAgID/gICA\r\n//////////////////f39/+AgID/gICA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAHh4eAGAgID/fX19/4CAgP+AgID/gICA/4CAgP99fX3/gICA/wAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9fX39gICA/4CAgP+AgID/gICA/4CA\r\ngP+AgID/fX19/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAABoaGj/aGho/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmZmb/ZmZm/wAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AXV1dQ1oaGj/\r\naGho/3R0dAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAB9fX39gICA/4CAgP+AgID/gICA/4CAgP+AgID/fX19/AAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eAGAgID/fX19/4CAgP+AgID/gICA/4CAgP99fX3/gICA\r\n/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eBaAgID/gICA////\r\n//////////////f39/+AgID/gICA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAHh4eBaAgID/gICA//////////////////f39/+AgID/gICA/2hoaP9mZmb/ZmZm/2Zm\r\nZv9mZmb/ZmZm/2ZmZv9oaGj/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eBaAgID/gICA//////////////////f39/+A\r\ngID/gICA/2hoaP9mZmb/ZmZm/2ZmZv9mZmb/ZmZm/2ZmZv9oaGj/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHh4eBaAgID/\r\ngICA//////////////////f39/+AgID/gICA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAHh4eAGAgID/fX19/4CAgP+AgID/gICA/4CAgP99fX3/gICA/wAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9fX39gICA/4CAgP+AgID/gICA\r\n/4CAgP+AgID/fX19/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAABoaGj/aGho/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmZmb/ZmZm/wAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABm\r\nZmb/ZmZm/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAABmZmb/ZmZm/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoaGj/aGho/wAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAACzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAACzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////AAD///////8AAPgH+AAABwAA\r\n8Af4AAAHAADwB/gAAAcAAPAAAAAABwAA8AAAAAAHAADwB/gAAAcAAPAH+AAABwAA+Af4AAAHAAD/\r\nP/////8AAP8//////wAA/z//////AAD4B/gAAAcAAPAH+AAABwAA8Af4AAAHAADwAAAAAAcAAPAA\r\nAAAABwAA8Af4AAAHAADwB/gAAAcAAPgH+AAABwAA/z//////AAD/P/////8AAPwf/////wAA+Af4\r\nAAAHAADwB/gAAAcAAPAH+AAABwAA8AAAAAAHAADwAAAAAAcAAPAH+AAABwAA8Af4AAAHAAD4B/gA\r\nAAcAAP8//////wAA/z//////AAD/P/////8AAP8//////wAA/z//////AADAAAAP//8AAMAAAA//\r\n/wAAwAAAD///AADAAAAP//8AAMAAAA///wAAwAAAD///AADAAAAP//8AAMAAAA///wAA////////\r\nAAD///////8AAP///////wAAKAAAACgAAABQAAAAAQAgAAAAAABAGgAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAfX19/4CAgP+AgID/gICA/4CAgP+AgID/fX19/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nALN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+ydz3/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAgP//\r\n/////////////////////////4CAgP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/snc9/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgID/////////////////\r\n//////////+AgID/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7J3Pf+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA////////////////////////////gICA\r\n/2ZmZv9mZmb/ZmZm/2ZmZv9mZmb/ZmZm/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+ydz3/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAICAgP///////////////////////////4CAgP9ycnINAAAAAAAA\r\nAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/snc9/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv8AAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAACAgID///////////////////////////+AgID/dnZ2BQAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7J3\r\nPf+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfX19\r\n/YCAgP+AgID/gICA/4CAgP+AgID/fX19/QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+ydz3/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZm\r\nZv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+AbN4PgGzeD4Bs3g+\r\nAbN4PgGzeD4Bs3g+AbN4PgGzeD4Bs3g+AbN4PgGzeD4Bs3g+AbN4PgGzeD4Bs3g+AbN4PgGzeD4B\r\ns3g+AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmZmb/AAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZmZm/wAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAH19ff+AgID/gICA/4CAgP+AgID/gICA/319ff4AAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAACzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\nsnc9/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA\r\ngID///////////////////////////+AgID/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7J3Pf+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA////////////\r\n////////////////gICA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+ydz3/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAgP//////////////////////////\r\n/4CAgP9mZmb/ZmZm/2ZmZv9mZmb/ZmZm/2ZmZv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/snc9/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv8A\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgID///////////////////////////+AgID/cnJyDQAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7J3Pf+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAgICA////////////////////////////gICA/3Z2dgUAAAAAAAAAAAAAAAAA\r\nAAAAAAAAALN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+ydz3/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAH19ff2AgID/gICA/4CAgP+AgID/gICA/319ff0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/snc9/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAABmZmb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PgGzeD4Bs3g+\r\nAbN4PgGzeD4Bs3g+AbN4PgGzeD4Bs3g+AbN4PgGzeD4Bs3g+AbN4PgGzeD4Bs3g+AbN4PgGzeD4B\r\ns3g+AbN4PgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZmZm/wAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZmZv8AAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAB9fX3/gICA/4CAgP+AgID/gICA/4CAgP99fX3+AAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7J3Pf+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAgICA////////////////////////////gICA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+ydz3/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAgP//////\r\n/////////////////////4CAgP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/snc9/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgID/////////////////////\r\n//////+AgID/ZmZm/2ZmZv9mZmb/ZmZm/2ZmZv9mZmb/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7J3Pf+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA////////////////////////////gICA/3Jy\r\ncg0AAAAAAAAAAAAAAAAAAAAAAAAAALN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+ydz3/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAICAgP///////////////////////////4CAgP92dnYFAAAAAAAAAAAA\r\nAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/snc9/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv8AAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAB9fX39gICA/4CAgP+AgID/gICA/4CAgP99fX39AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7J3Pf+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAZmZm/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD4Bs3g+\r\nArN4PgOzeD4Es3g+BLN4PgSzeD4Es3g+BLN4PgSzeD4Es3g+BLN4PgSzeD4Es3g+BLN4PgSzeD4D\r\ns3g+ArN4PgGzeD4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZmZv8A\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmZmb/AAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZmZm/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACz\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/snc9/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7J3Pf+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+ydz3/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/snc9/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7J3Pf+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv8AAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nALN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+ydz3/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/snc9\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAD//////wAAAPAfgAADAAAA8B+AAAMAAADwH4AAAwAAAPAAAAADAAAA\r\n8A+AAAMAAADwD4AAAwAAAPAfgAADAAAA/v/AAAcAAAD+/////wAAAP7/////AAAA8B+AAAMAAADw\r\nH4AAAwAAAPAfgAADAAAA8AAAAAMAAADwD4AAAwAAAPAPgAADAAAA8B+AAAMAAAD+/8AABwAAAP7/\r\n////AAAA/v////8AAADwH4AAAwAAAPAfgAADAAAA8B+AAAMAAADwAAAAAwAAAPAPgAADAAAA8A+A\r\nAAMAAADwH4AAAwAAAP7/wAAHAAAA/v////8AAAD+/////wAAAP7/////AAAAwAAAf/8AAADAAAB/\r\n/wAAAMAAAH//AAAAwAAAf/8AAADAAAB//wAAAMAAAH//AAAAwAAAf/8AAAD//////wAAACgAAAAg\r\nAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAH19ff6AgID/gICA/4CAgP99fX3+AAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+AwAA\r\nAAAAAAAAAAAAAAAAAAB4eHgCgICA/////////////////4CAgP9ycnIJAAAAAAAAAAAAAAAAAAAA\r\nALN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD4DAAAAAAAAAAAAAAAAAAAAAHh4eAKAgID/////////////////gICA/2hoaP9o\r\naGj/aGho/2hoaP9oaGj/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgMAAAAAAAAAAAAAAAAAAAAAeHh4AYCAgP/7+/v/+/v7\r\n//v7+/+AgID/cXFxCQAAAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+AwAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAfX19/oCAgP+AgID/gICA/319ff4AAAAAAAAAAAAAAAAAAAAAAAAAALN4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4DAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhoaOwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\ns3g+BrN4PgyzeD4Ss3g+ErN4PhKzeD4Ms3g+BrN4PgazeD4Gs3g+BrN4PgazeD4Gs3g+BrN4Pgaz\r\neD4Gs3g+BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaGho7AAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFxcQxoaGjt\r\ncHBwDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAB9fX3+gICA/4CAgP+AgID/fX19/gAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgMAAAAA\r\nAAAAAAAAAAAAAAAAeHh4AoCAgP////////////////+AgID/cnJyCQAAAAAAAAAAAAAAAAAAAACz\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+AwAAAAAAAAAAAAAAAAAAAAB4eHgCgICA/////////////////4CAgP9oaGj/aGho\r\n/2hoaP9oaGj/aGho/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4DAAAAAAAAAAAAAAAAAAAAAHh4eAGAgID/+/v7//v7+//7\r\n+/v/gICA/3FxcQkAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgMAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAH19ff6AgID/gICA/4CAgP99fX3+AAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+AwAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoaGjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4\r\nPgazeD4Ms3g+ErN4PhKzeD4Ss3g+DLN4PgazeD4Gs3g+BrN4PgazeD4Gs3g+BrN4PgazeD4Gs3g+\r\nBrN4PgYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhoaOwAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABxcXEMaGho7XBw\r\ncAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nfX19/oCAgP+AgID/gICA/319ff4AAAAAAAAAAAAAAAAAAAAAAAAAALN4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4DAAAAAAAA\r\nAAAAAAAAAAAAAHh4eAKAgID/////////////////gICA/3JycgkAAAAAAAAAAAAAAAAAAAAAs3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4PgMAAAAAAAAAAAAAAAAAAAAAeHh4AoCAgP////////////////+AgID/aGho/2hoaP9o\r\naGj/aGho/2hoaP+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+AwAAAAAAAAAAAAAAAAAAAAB4eHgBgICA//v7+//7+/v/+/v7\r\n/4CAgP9xcXEJAAAAAAAAAAAAAAAAAAAAALN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4DAAAAAAAAAAAAAAAAAAAAAAAAAAB9\r\nfX3+gICA/4CAgP+AgID/fX19/gAAAAAAAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgMAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAaGho7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD4G\r\ns3g+DLN4PhKzeD4Ss3g+ErN4PgyzeD4Gs3g+BrN4PgazeD4Gs3g+BrN4PgazeD4Gs3g+BrN4Pgaz\r\neD4GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoaGjsAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhoaOwAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD75s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4PgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAALN4PvmzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAs3g++bN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4DAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD75s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PvmzeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAs3g++bN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD4DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAACzeD4Gs3g+BrN4PgazeD4Gs3g+BrN4PgazeD4Gs3g+BrN4PgazeD4G\r\ns3g+DLN4PhKzeD4Ss3g+ErN4PhKzeD4Ss3g+DLN4PgYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////+D4AAPAeAADwAAAA8B4AAPg+AAD+/gAB/v/\r\n///x////4PgAA8B4AAPAAAADwHgAA+D4AAP7+AAH+/////H////g+AADwHgAA8AAAAPAeAAD4PgA\r\nA/v4AAf7////+////4AAA/+AAAP/gAAD/4AAA/+AAAP/gAAD/4AAH/8oAAAAGAAAADAAAAABACAA\r\nAAAAAGAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nfX19/oCAgP+AgID/gICA/319ff4AAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAB4eHgCgICA/////////////////4CA\r\ngP9ycnIJAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/AAAAAAAAAAB4eHgCgICA/////////////////4CAgP9oaGj/aGho/2hoaP9oaGj/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAB4\r\neHgBgICA//v7+//7+/v/+/v7/4CAgP9xcXEJAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAfX19/oCAgP+AgID/gICA\r\n/319ff4AAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAAAABoaGjsAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAACzeD4Gs3g+BrN4PgazeD4Gs3g+BrN4PgazeD4Gs3g+BgAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAABoaGjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFxcQxoaGjt\r\ncHBwDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfX19/oCAgP+AgID/gICA/319ff4AAAAAAAAAAAAA\r\nAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAA\r\nAAAAAAB4eHgCgICA/////////////////4CAgP9ycnIJAAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAB4eHgCgICA////////\r\n/////////4CAgP9oaGj/aGho/2hoaP9oaGj/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAB4eHgBgICA//v7+//7+/v/+/v7/4CAgP9xcXEJAAAA\r\nAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\nAAAAAAAAAAAAAAAAfX19/oCAgP+AgID/gICA/319ff4AAAAAAAAAAAAAAAAAAAAAs3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAAAAAAAAA\r\nAABoaGjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoaGjsAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoaGjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PvmzeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgMAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PvmzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAALN4PvmzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4PgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PvmzeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgMA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN4PvmzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgMAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wDg\r\n8AAAwHAAAMAAAADAcAAA4PAAAPv8AwD7//8A8f//AODwAADAcAAAwAAAAMBwAADg8AAA+///APv/\r\n/wD7//8AgAB/AIAAfwCAAH8AgAB/AIAAfwD///8AKAAAABQAAAAoAAAAAQAgAAAAAACQBgAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAfX19/oCAgP+AgID/gICA/319ff4AAAAAAAAAAAAAAACzeD7/\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAHh4eAKAgID/////////////\r\n////gICA/3JycgkAAAAAAAAAALN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv8AAAAAeHh4AoCAgP////////////////+AgID/aGho/2hoaP9oaGj/s3g+/7N4Pv+zeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAB4eHgBgICA//v7+//7+/v/+/v7/4CAgP9xcXEJ\r\nAAAAAAAAAACzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAB9\r\nfX3+gICA/4CAgP+AgID/fX19/gAAAAAAAAAAAAAAALN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv8AAAAAAAAAAAAAAAAAAAAAaGho/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFxcQxoaGjt\r\ncHBwDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAB9fX3+gICA/4CAgP+AgID/fX19/gAAAAAAAAAAAAAAALN4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv8AAAAAeHh4AoCAgP////////////////+AgID/cnJy\r\nCQAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAB4eHgC\r\ngICA/////////////////4CAgP9oaGj/aGho/2hoaP+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/AAAAAHh4eAGAgID/+/v7//v7+//7+/v/gICA/3FxcQkAAAAAAAAAALN4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv8AAAAAAAAAAH19ff6AgID/gICA\r\n/4CAgP99fX3+AAAAAAAAAAAAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/wAAAAAAAAAAAAAAAAAAAABoaGjsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhoaOwAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAaGho7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAALN4PvmzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgMAAAAAAAAAAAAAAAAAAAAAs3g++bN4Pv+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+AwAAAAAAAAAAAAAA\r\nAAAAAACzeD75s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/\r\ns3g+/7N4Pv+zeD4Ds3g+AwAAAAAAAAAAAAAAALN4PvmzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4PgMAAAAAAAAAAAAAAAAAAAAAs3g++bN4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\nAwAAAAAAAAAAAAAAAAAAAADBwAAAgMAAAIAAAACAwAAAwcAAAPf/8ADj//AAwcAAAIDAAACAAAAA\r\ngMAAAMHAAAD3//AA9//wAPf/8AAAAPAAAADwAAAAcAAAAPAAAADwACgAAAAQAAAAIAAAAAEAIAAA\r\nAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAB4eHgCfX19/4CAgP+AgID/gICA/319ff9ycnIJAAAAALN4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/eHh4AoCAgP////////////////+AgID/aGho\r\n/2hoaP+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/3h4eAyAgID/+/v7//v7+//7+/v/\r\ngICA/3FxcQkAAAAAs3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv94eHgLfX19/oCAgP+A\r\ngID/gICA/319ff4AAAAAAAAAALN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/eHh4CwAA\r\nAAAAAAAAaGho/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAHh4eAsAAAAAcXFxDGhoaO1wcHAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAB4eHgCfX19/4CAgP+AgID/gICA/319ff9ycnIJAAAAALN4Pv+zeD7/s3g+/7N4Pv+z\r\neD7/s3g+/7N4Pv+zeD7/eHh4AoCAgP////////////////+AgID/aGho/2hoaP+zeD7/s3g+/7N4\r\nPv+zeD7/s3g+/7N4Pv+zeD7/s3g+/3h4eAyAgID/+/v7//v7+//7+/v/gICA/3FxcQkAAAAAs3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv94eHgLfX19/oCAgP+AgID/gICA/319ff4AAAAA\r\nAAAAALN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAAAAAAAAAAaGho7AAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGho\r\naOwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzeD7/s3g+\r\n/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/wAAAAAAAAAAAAAAAAAAAAAAAAAA\r\ns3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv8AAAAAAAAAAAAAAAAA\r\nAAAAAAAAALN4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/AAAAAAAA\r\nAAAAAAAAAAAAAAAAAACzeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+/7N4Pv+zeD7/s3g+\r\n/wAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAwAAAG//AABH/wAAAQAAAAAAAAABAAAA\r\nAwAAAO//AADv/wAAAB8AAAAfAAAAHwAAAB8AAA==')\r\n\t#endregion\r\n\t$formOUSelection.MaximizeBox = $False\r\n\t$formOUSelection.MinimizeBox = $False\r\n\t$formOUSelection.Name = 'formOUSelection'\r\n\t$formOUSelection.SizeGripStyle = 'Hide'\r\n\t$formOUSelection.StartPosition = 'CenterParent'\r\n\t$formOUSelection.Text = 'OU Selection'\r\n\t$formOUSelection.add_FormClosing($formOUSelection_FormClosing)\r\n\t$formOUSelection.add_Load($formOUSelection_Load)\r\n\t#\r\n\t# checkboxUseDomainRootInstead\r\n\t#\r\n\t$checkboxUseDomainRootInstead.Location = '13, 359'\r\n\t$checkboxUseDomainRootInstead.Name = 'checkboxUseDomainRootInstead'\r\n\t$checkboxUseDomainRootInstead.Size = '241, 24'\r\n\t$checkboxUseDomainRootInstead.TabIndex = 4\r\n\t$checkboxUseDomainRootInstead.Text = 'Use Domain Root Instead Of Selected OU'\r\n\t$checkboxUseDomainRootInstead.UseCompatibleTextRendering = $True\r\n\t$checkboxUseDomainRootInstead.UseVisualStyleBackColor = $True\r\n\t#\r\n\t# treeview1\r\n\t#\r\n\t$treeview1.Location = '13, 13'\r\n\t$treeview1.Name = 'treeview1'\r\n\t$treeview1.Size = '615, 329'\r\n\t$treeview1.TabIndex = 3\r\n\t$treeview1.add_AfterSelect($treeview1_AfterSelect)\r\n\t#\r\n\t# buttonOk\r\n\t#\r\n\t$buttonOk.DialogResult = 'OK'\r\n\t$buttonOk.Location = '553, 359'\r\n\t$buttonOk.Name = 'buttonOk'\r\n\t$buttonOk.Size = '75, 23'\r\n\t$buttonOk.TabIndex = 2\r\n\t$buttonOk.Text = '&Ok'\r\n\t$buttonOk.UseCompatibleTextRendering = $True\r\n\t$buttonOk.UseVisualStyleBackColor = $True\r\n\t$buttonOk.add_Click($buttonOk_Click)\r\n\t#\r\n\t# imagelistLargeImages\r\n\t#\r\n\t$imagelistLargeImages.ColorDepth = 'Depth32Bit'\r\n\t$imagelistLargeImages.ImageSize = '32, 32'\r\n\t$imagelistLargeImages.TransparentColor = 'Transparent'\r\n\t#\r\n\t# imagelistSmallImages\r\n\t#\r\n\t$imagelistSmallImages.ColorDepth = 'Depth32Bit'\r\n\t$imagelistSmallImages.ImageSize = '16, 16'\r\n\t$imagelistSmallImages.TransparentColor = 'Transparent'\r\n\t$formOUSelection.ResumeLayout()\r\n\t#endregion Generated Form Code\r\n\r\n\t#----------------------------------------------\r\n\r\n\t#Save the initial state of the form\r\n\t$InitialFormWindowState = $formOUSelection.WindowState\r\n\t#Init the OnLoad event to correct the initial state of the form\r\n\t$formOUSelection.add_Load($Form_StateCorrection_Load)\r\n\t#Clean up the control events\r\n\t$formOUSelection.add_FormClosed($Form_Cleanup_FormClosed)\r\n\t#Store the control values when form is closing\r\n\t$formOUSelection.add_Closing($Form_StoreValues_Closing)\r\n\t#Show the Form\r\n\treturn $formOUSelection.ShowDialog()\r\n\r\n}\r\n#endregion Source: OU Selector.psf\r\n\r\n#Start the application\r\nMain ($CommandLine)\r\n\r\n\r\nImport-Module ActiveDirectory\r\n[System.Collections.ArrayList]$array = @()\r\n[System.Collections.ArrayList]$pathArray = @()\r\n\r\n#$script:ConfigFilePath = \"$CustomProperty.ConfigFilePath$\\RoyalTSDynamicFolderCustomizer\"\r\nif (\"$CustomProperty.ConfigFilePath$\" -ne '.ConfigFilePath$' -and \"$CustomProperty.ConfigFilePath$\" -ne \"TODO\")\r\n{\r\n\t$script:ConfigFilePath = \"$CustomProperty.ConfigFilePath$\"\r\n}\r\nelse\r\n{\r\n\t$script:ConfigFilePath = \"$($env:APPDATA)\\RoyalTSDynamicFolderCustomizer\"\r\n}\r\nif (\"$CustomProperty.ConfigFileName$\" -ne '.ConfigFileName$' -and \"$CustomProperty.ConfigFileName$\" -ne \"TODO\")\r\n{\r\n\t$script:configFileName = \"$CustomProperty.ConfigFileName$\"\r\n}\r\nelse\r\n{\r\n\t$script:configFileName = \"settings.xml\"\r\n}\r\nif (Test-Path \"$($script:ConfigFilePath)\\$($configFileName)\")\r\n{\r\n\t$data = Import-Clixml -Path \"$($script:ConfigFilePath)\\$($configFileName)\"\r\n\t$filter = $data.filter\r\n\t$searchScope = $data.searchscope\r\n\t$server = $data.server\r\n\t$searchBase = $data.searchbase\r\n\tif ($($data.useCimChecked) -like \"Checked\")\r\n\t{\r\n\t\t$useCim = \"true\"\r\n\t}\r\n\telse\r\n\t{\r\n\t\t$useCim = \"false\"\r\n\t}\r\n\tif ($($data.adminConsole) -like \"Checked\")\r\n\t{\r\n\t\t$useadminConsole = \"true\"\r\n\t}\r\n\telse\r\n\t{\r\n\t\t$useadminConsole = \"false\"\r\n\t}\r\n\t\r\n\tforeach ($computer in Get-ADComputer -SearchBase $searchBase -filter $filter -SearchScope $searchScope -Server $server -Properties canonicalname,Description)\r\n\t{\r\n\t\tif ($data.useParentCred -eq $true)\r\n\t\t{\r\n\t\t\t$subPath = $computer.canonicalname.replace(\"/$($computer.name)\", \"\")\r\n\t\t\t$initialCounter = 0\r\n\t\t\tforeach ($pathItem in $subPath.split(\"/\"))\r\n\t\t\t{\r\n\t\t\t\tif ($initialCounter -eq 0)\r\n\t\t\t\t{\r\n\t\t\t\t\t$builderPath = \"/\"\r\n\t\t\t\t\t$initialCounter++\r\n\t\t\t\t\t$previousPath = $pathItem\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\t$builderPath = \"$($builderPath)/$previousPath\".replace('//', '/')\r\n\t\t\t\t\t$previousPath = $pathItem\r\n\t\t\t\t\t\r\n\t\t\t\t}\r\n\t\t\t\tif ($pathArray.Contains(\"$($builderPath)/$pathItem\"))\r\n\t\t\t\t{\r\n\t\t\t\t\t\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\t$array.add((\r\n\t\t\t\t\t\t\tNew-Object -TypeName System.Management.Automation.PSObject -Property @{\r\n\t\t\t\t\t\t\t\t\"Type\"\t\t\t = \"Folder\";\r\n\t\t\t\t\t\t\t\t\"CredentialsFromParent\" = \"true\";\r\n\t\t\t\t\t\t\t\t\"Path\"\t\t\t = $builderPath;\r\n\t\t\t\t\t\t\t\t\"Name\"\t\t\t = $pathItem;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t)) | Out-Null\r\n\t\t\t\t\t$pathArray.add(\"$($builderPath)/$pathItem\") | Out-Null\r\n\t\t\t\t}\r\n\t\t\t} \r\n\t\t}\r\n\t\tif ($($data.connectionType) -like \"RemoteDesktopConnection\")\r\n\t\t{\r\n\t\t\t$array.add((\r\n\t\t\t\t\tNew-Object -TypeName System.Management.Automation.PSObject -Property @{\r\n\t\t\t\t\t\t\"Type\" = $data.connectionType;\r\n\t\t\t\t\t\t\"Port\" = $data.portNumber\r\n\t\t\t\t\t\t\"Name\" = $computer.name;\r\n\t\t\t\t\t\t\"ComputerName\" = $computer.name;\r\n\t\t\t\t\t\t\"Description\" = $computer.Description;\r\n\t\t\t\t\t\t\"credentialName\" = $data.credentialName;\r\n\t\t\t\t\t\t\"Path\" = \"/\" +$computer.canonicalname.replace(\"/$($computer.name)\", \"\");\r\n\t\t\t\t\t\t\"ConsoleSession\" = $useadminConsole;\r\n\t\t\t\t\t\t\"CredentialsFromParent\" = $data.useParentCred;\r\n\t\t\t\t\t}\r\n\t\t\t\t)) | Out-Null\r\n\t\t}\r\n\t\telseif ($($data.connectionType) -like \"TerminalConnection*\")\r\n\t\t{\r\n\t\t\t$array.add((\r\n\t\t\t\t\tNew-Object -TypeName System.Management.Automation.PSObject -Property @{\r\n\t\t\t\t\t\t\"Type\"\t\t\t = \"TerminalConnection\";\r\n\t\t\t\t\t\t\"TerminalConnectionType\" = $($data.connectionType).replace(\"TerminalConnection - \", \"\")\r\n\t\t\t\t\t\t\"Port\"\t\t\t = $data.portNumber\r\n\t\t\t\t\t\t\"Name\"\t\t\t = $computer.name;\r\n\t\t\t\t\t\t\"ComputerName\"\t\t = $computer.name;\r\n\t\t\t\t\t\t\"credentialName\"\t = $data.credentialName;\r\n\t\t\t\t\t\t\"Path\"\t\t\t = \"/\" +$computer.canonicalname.replace(\"/$($computer.name)\", \"\");\r\n\t\t\t\t\t\t\"CredentialsFromParent\" = $data.useParentCred;\r\n\t\t\t\t\t}\r\n\t\t\t\t)) | Out-Null\r\n\t\t}\r\n\t\telseif ($($data.connectionType) -like \"Windows*\" -or $($data.connectionType) -like \"TerminalServicesConnection\")\r\n\t\t{\r\n\t\t\t$array.add((\r\n\t\t\t\t\tNew-Object -TypeName System.Management.Automation.PSObject -Property @{\r\n\t\t\t\t\t\t\"Type\" = $data.connectionType;\r\n\t\t\t\t\t\t\"UseCIM\" = $useCim;\r\n\t\t\t\t\t\t\"Name\" = $computer.name;\r\n\t\t\t\t\t\t\"ComputerName\" = $computer.name;\r\n\t\t\t\t\t\t\"Description\" = $computer.Description;\r\n\t\t\t\t\t\t\"credentialName\" = $data.credentialName;\r\n\t\t\t\t\t\t\"Path\" = \"/\" +$computer.canonicalname.replace(\"/$($computer.name)\", \"\");\r\n\t\t\t\t\t\t\"CredentialsFromParent\" = $data.useParentCred;\r\n\t\t\t\t\t}\r\n\t\t\t\t)) | Out-Null\r\n\t\t}\r\n\t\telseif ([string]::IsNullOrEmpty($data.portNumber))\r\n\t\t{\r\n\t\t\t$array.add((\r\n\t\t\t\t\tNew-Object -TypeName System.Management.Automation.PSObject -Property @{\r\n\t\t\t\t\t\t\"Type\" = $data.connectionType;\r\n\t\t\t\t\t\t\"Name\" = $computer.name;\r\n\t\t\t\t\t\t\"ComputerName\" = $computer.name;\r\n\t\t\t\t\t\t\"credentialName\" = $data.credentialName;\r\n\t\t\t\t\t\t\"Path\" = \"/\"+$computer.canonicalname.replace(\"/$($computer.name)\", \"\");\r\n\t\t\t\t\t\t\"CredentialsFromParent\" = $data.useParentCred;\r\n\t\t\t\t\t}\r\n\t\t\t\t)) | Out-Null\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t$array.add((\r\n\t\t\t\t\tNew-Object -TypeName System.Management.Automation.PSObject -Property @{\r\n\t\t\t\t\t\t\"Type\" = $data.connectionType;\r\n\t\t\t\t\t\t\"Port\" = $data.portNumber\r\n\t\t\t\t\t\t\"Name\" = $computer.name;\r\n\t\t\t\t\t\t\"ComputerName\" = $computer.name;\r\n\t\t\t\t\t\t\"credentialName\" = $data.credentialName;\r\n\t\t\t\t\t\t\"Path\" = \"/\" +$computer.canonicalname.replace(\"/$($computer.name)\", \"\");\r\n\t\t\t\t\t\t\"CredentialsFromParent\" = $data.useParentCred;\r\n\t\t\t\t\t}\r\n\t\t\t\t)) | Out-Null\r\n\t\t}\r\n\t\t\r\n\t}\r\n\t$newarray = $array | Sort-Object -Property Name\r\n\t$hash = @{ }\r\n\t$hash.add(\"Objects\", $newarray)\r\n\t[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8\r\n\t$hash | ConvertTo-Json\r\n\r\n}\r\n", - "ScriptInterpreter": "powershell", - "DynamicCredentialScriptInterpreter": "json" - } - ] -} diff --git a/Dynamic Folder/Active Directory/AD Servers (Windows PowerShell).rdfx b/Dynamic Folder/Active Directory/AD Servers (Windows PowerShell).rdfx new file mode 100644 index 0000000..43eb0bb --- /dev/null +++ b/Dynamic Folder/Active Directory/AD Servers (Windows PowerShell).rdfx @@ -0,0 +1,2426 @@ + + Dynamic Folder Export + + + DynamicFolder + AD Servers (Windows PowerShell) + This script allows you to query Active Directory to add computers from your Active Directory environment to RoyalTS. + + + +

This script requires Windows PowerShell 4.x/5.x as well as the Active Directory

+ +

Powershell Cmdlets.

+ +

 

+ +

This script allows you to query Active Directory to add computers from your Active Directory environment to RoyalTS.

+ +

 

+ +

To use this application, update the Custom Property ConfigFileName with the name of the configuration file for the dynamic folder.  This allows you to configure multiple dynamic folders using the same script without having to update the Custom Properties multiple times - the only time will be to set the setting file name.  If this field is not updated, the setting file will be set as Settings.xml.

+ +

 

+ +

Upon launching the form the first time, you are prompted to fill in a few settings.

+ +

The first setting is the domain name.  After you type in the domain name, the ldap dc path and Primary Domain Controller Emulator will autopopulate the DC Root and DC fields.  

+ +

 

+ +

The next field to fill in is the Connection Type dropdown.  This list contains all of the valid connection types the script is able to connect.  Depending on what option is selected other options will appear below the dropdown.  These settings include if the connection should use Cim sessions, what port number to use, and if the connection should be a admin/console connection.

+ +

 

+ +

The next field to fill in is the Credential Name.  This is the name of the credential in RoyalTS to have the computers open up with.  If you wish to set the credentials at the Dynamic Folder level in the same way of typical folders, you can leave this field blank and all the connections will be set to auto inherit their credentials from the Dynamic Folder.

+ +

 

+ +

SearchBase takes in the OU Path that the computers should be located in.  You can populate this field by clicking on the button to the right of the text box.  This button will load a GUI to select the correct OU.

+ +

 

+ +

SearchScope is how to search under the selected OU entered in SearchBase.  The three options under here are:

+ +
    +
  1. Base - only computers contained in the selected OU are listed
  2. +
  3. SubTree - all computers in all of the OUs under the selected OU are listed
  4. +
  5. OneLevel - all computers in the OUs one level under the selcted OU are listed
  6. +
+ +

 

+ +

The filter field allows for adding in filters which are compatible with the PowerShell AD CMDLTS.  By default the filter is * which will return all comptuers.  Example filters are below.

+ +
    +
  1. name -like 'test*'
  2. +
  3. name -eq 'testpd09'
  4. +
+ +

 

+ +

After your settings are entered, click Submit to save the data.

+ +

 

+ +

Every time you run the script to enumerate the computers, the Royal TS Dynamic Folder Configurator dialog will appear.  If the mouse is not moved over the screen within five seconds, the dialog assumes no data needs to be modified for the filter and the current selected filter is accepted.  

+ +

 

+ +

If the configuration file is missing and cannot be loaded by the script, then the dialog will not automatically close as these settings are required to produce a list of computers.

+ +

 

+ +

Configuration Walkthrough Video: https://youtu.be/wMnqSQd1tYU

+ +

 

+ +

Version: 1.1

+ +

Author: Paul DeArment Jr

+ +

Twitter: pdearmen

+ +

Github: https://github.com/armentpau

+]]>
+ + + ConfigFileName + Text + TODO + + + ConfigFilePath + Text + TODO + + + powershell + + json + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file diff --git a/Dynamic Folder/Active Directory/Active Directory (Python).rdfe b/Dynamic Folder/Active Directory/Active Directory (Python).rdfe deleted file mode 100644 index c5e1c34..0000000 --- a/Dynamic Folder/Active Directory/Active Directory (Python).rdfe +++ /dev/null @@ -1,27 +0,0 @@ -{ - "Name": "Dynamic Folder Export", - "Objects": [ - { - "Type": "DynamicFolder", - "Name": "Active Directory (Python)", - "Description": "This Dynamic Folder sample allows you to import connections from Active Directory or any other LDAP-based directory.", - "Notes": "

Active Directory/LDAP Dynamic Folder sample

\n\n

Version: 1.0
\nAuthor: Royal Applications

\n\n

This Dynamic Folder sample allows you to import connections from Active Directory or any other LDAP-based directory. It scans a configurable domain controller/LDAP server for computer objects and stores them in folders mimicking the OU structure of the directory. Based on the operating system of the computer object, either a Remote Desktop (Windows), a VNC (macOS) or an SSH (Linux) connection will be created. The "Custom Properties" section contains configuration parameters which must be populated before reloading the dynamic folder. Please also ensure that valid credentials for accessing the specified domain controller/LDAP server are configured in the "Credentials" section.

\n\n

Requirements

\n\n\n\n

Setup

\n\n\n", - "CustomProperties": [ - { - "Name": "DC/LDAP Server", - "Type": "Text", - "Value": "TODO" - }, - { - "Name": "Search Base", - "Type": "Text", - "Value": "TODO" - } - ], - "ScriptInterpreter": "python", - "DynamicCredentialScriptInterpreter": "json", - "DynamicCredentialScript": "{\n\t\"Username\": \"user\",\n\t\"Password\": \"pass\"\n}", - "Script": "import json\nimport ldap\n\nLDAP_SERVER = r\"$CustomProperty.DCLDAPServer$\" # i.e. 'mydomain.local' / '192.168.0.1'\nLDAP_USERNAME = r\"$EffectiveUsername$\"\nLDAP_PASSWORD = r\"$EffectivePassword$\"\nBASE_DN = r\"$CustomProperty.SearchBase$\" # i.e. 'DC=mydomain,DC=local'\n\nLDAP_CONNECTION_STRING = \"ldap://\" + LDAP_SERVER\nSEARCH_FILTER = \"objectCategory=computer\"\n\nATTRIBUTE_CN = \"cn\"\nATTRIBUTE_DNS_HOSTNAME = \"dNSHostName\"\nATTRIBUTE_NETWORK_ADDRESS = \"networkAddress\"\nATTRIBUTE_OPERATING_SYSTEM = \"operatingSystem\"\nATTRIBUTES_TO_QUERY = [ ATTRIBUTE_CN, ATTRIBUTE_DNS_HOSTNAME, ATTRIBUTE_NETWORK_ADDRESS, ATTRIBUTE_OPERATING_SYSTEM ]\n\nOS_WINDOWS = \"windows\"\nOS_MACOS = \"macos\"\nOS_LINUX = \"linux\"\n\nOS_OBJECT_TYPE_MAPPING = {\n\tOS_WINDOWS: \"RemoteDesktopConnection\",\n\tOS_MACOS: \"VNCConnection\",\n\tOS_LINUX: \"TerminalConnection\"\n}\n\ndef create_connection(object_type, terminal_connection_type, name, host, path):\n\tconnection = {\n\t\t\"Type\": object_type,\n\t\t\"Name\": name,\n\t\t\"ComputerName\": host\n\t}\n\n\tif path is not None and path != \"\":\n\t\tconnection[\"Path\"] = path\n\n\treturn connection\n\n\ndef get_object_type(os):\n\tobject_type = OS_OBJECT_TYPE_MAPPING[os]\n\n\treturn object_type\n\n\ndef get_os(operating_system):\n\tos = OS_WINDOWS\n\n\tif operating_system is not None:\n\t\toperating_system_lower = operating_system.lower()\n\n\t\tif operating_system_lower.startswith(\"windows\"):\n\t\t\tos = OS_WINDOWS\n\t\telif operating_system_lower.startswith(\"mac os\"):\n\t\t\tos = OS_MACOS\n\t\telse:\n\t\t\tos = OS_LINUX\n\n\treturn os\n\n\ndef get_entry_value(entry, attribute):\n\tval = None\n\n\tif attribute in entry:\n\t\tval_list = entry[attribute]\n\t\t\n\t\tif isinstance(val_list, list):\n\t\t\tif len(val_list) > 0:\n\t\t\t\tval_potential = val_list[0]\n\t\t\t\t\n\t\t\t\tif isinstance(val_potential, str):\n\t\t\t\t\tval = val_potential\n\t\t\t\telif isinstance(val_potential, bytes):\n\t\t\t\t\tval = val_potential.decode()\n\n\treturn val\n\n\ndef get_ldap_result(ldap_connection_string, ldap_username, ldap_password, base_dn):\n\tad = ldap.initialize(ldap_connection_string)\n\tad.set_option(ldap.OPT_REFERRALS, 0) # to search the object and all its descendants\n\tad.simple_bind_s(ldap_username, ldap_password)\n\n\tresult = ad.search_s(base_dn, ldap.SCOPE_SUBTREE, SEARCH_FILTER, ATTRIBUTES_TO_QUERY)\n\n\treturn result\n\n\ndef get_path(dn, computer_cn):\n\tdn_arr = dn.split(\",\")\n\t\n\tpath_arr = []\n\n\tfor part in dn_arr:\n\t\tpart_lower = part.lower()\n\n\t\tif part_lower.startswith(\"ou=\") or part_lower.startswith(\"cn=\"):\n\t\t\tpart_val_arr = part.split(\"=\")\n\n\t\t\tif len(part_val_arr) > 1:\n\t\t\t\tpart_val = part_val_arr[1]\n\n\t\t\t\tif computer_cn != part_val:\n\t\t\t\t\tpath_arr.append(part_val)\n\n\tpath_arr.reverse()\n\n\tpath = \"/\".join(path_arr)\n\n\treturn path\n\n\ndef ldap_entry_to_connection(dn, entry):\n\tcomputer_cn = get_entry_value(entry, ATTRIBUTE_CN)\n\n\tpath = get_path(dn, computer_cn)\n\n\tdns_hostname = get_entry_value(entry, ATTRIBUTE_DNS_HOSTNAME)\n\tnetwork_address = get_entry_value(entry, ATTRIBUTE_NETWORK_ADDRESS)\n\t\n\tos = get_os(get_entry_value(entry, ATTRIBUTE_OPERATING_SYSTEM))\n\t\n\tobject_type = get_object_type(os)\n\tterminal_connection_type = \"SSHConnection\"\n\n\tcomputer_name = dns_hostname\n\n\tif dns_hostname is None or dns_hostname == \"\":\n\t\tcomputer_name = network_address\n\n\tconnection = None\n\n\tif computer_name is not None and computer_name != \"\":\n\t\tconnection = create_connection(object_type, terminal_connection_type, computer_cn, computer_name, path)\n\n\treturn connection\n\n\ndef get_connections(ldap_connection_string, ldap_username, ldap_password, base_dn):\n\tresult = get_ldap_result(ldap_connection_string, ldap_username, ldap_password, base_dn)\n\n\tconnections = []\n\n\tif isinstance(result, list):\n\t\tfor dn, entry in result:\n\t\t\tif isinstance(entry, dict):\n\t\t\t\tconnection = ldap_entry_to_connection(dn, entry)\n\n\t\t\t\tif connection is None:\n\t\t\t\t\tcontinue\n\n\t\t\t\tconnections.append(connection)\n\n\treturn connections\n\n\nconnections = get_connections(LDAP_CONNECTION_STRING, LDAP_USERNAME, LDAP_PASSWORD, BASE_DN)\n\nstore = {\n\t\"Objects\": connections\n}\n\njsonStr = json.dumps(store)\n\nprint(jsonStr)" - } - ] -} \ No newline at end of file diff --git a/Dynamic Folder/Active Directory/Active Directory (Python).rdfx b/Dynamic Folder/Active Directory/Active Directory (Python).rdfx new file mode 100644 index 0000000..e45179a --- /dev/null +++ b/Dynamic Folder/Active Directory/Active Directory (Python).rdfx @@ -0,0 +1,220 @@ + + Dynamic Folder Export + + + DynamicFolder + Active Directory (Python) + This Dynamic Folder sample allows you to import connections from Active Directory or any other LDAP-based directory. + Active Directory/LDAP Dynamic Folder sample + +

Version: 1.0
+Author: Royal Applications

+ +

This Dynamic Folder sample allows you to import connections from Active Directory or any other LDAP-based directory. It scans a configurable domain controller/LDAP server for computer objects and stores them in folders mimicking the OU structure of the directory. Based on the operating system of the computer object, either a Remote Desktop (Windows), a VNC (macOS) or an SSH (Linux) connection will be created. The "Custom Properties" section contains configuration parameters which must be populated before reloading the dynamic folder. Please also ensure that valid credentials for accessing the specified domain controller/LDAP server are configured in the "Credentials" section.

+ +

Requirements

+ +
    +
  • Python Module: python-ldap
  • +
+ +

Setup

+ +
    +
  • Specify credentials for accessing the domain controller/LDAP server in the "Credentials" section.
  • +
  • Specify the domain controller/LDAP server in the "DC/LDAP Server" field of the "Custom Properties" section. This can either be a fully qualified domain name or an IP address. (Examples: "mydomain.local", "mydomaincontroller.mydomain.local", "192.168.0.1")
  • +
  • Specify the base search path in the "Search Base" field of the "Custom Properties" section. (Example: "DC=mydomain,DC=local")
  • +
+]]>
+ + + DC/LDAP Server + Text + TODO + + + Search Base + Text + TODO + + + python + + json + + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file diff --git a/Dynamic Folder/Active Directory/Basic Active Directory (Windows PowerShell).rdfe b/Dynamic Folder/Active Directory/Basic Active Directory (Windows PowerShell).rdfe deleted file mode 100644 index 8fc8dee..0000000 --- a/Dynamic Folder/Active Directory/Basic Active Directory (Windows PowerShell).rdfe +++ /dev/null @@ -1 +0,0 @@ -{"Name":"Dynamic Folder Export","Objects":[{"Type":"DynamicFolder","Name":"Basic Active Directory","Description": "In this example the Get-ADComputer commandlet is used to retrieve information from the Active Directory and shows all found computer objects in a tree structure mimicking the OU structure in the Active Directory.","Notes":"\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t

Dynamic Folder for Basic Active Directory Synchronization

 

Version: 1.0

Author: Paul DeArment, Royal Applications

 

This is a very basic dynamic folder example for Windows using PowerShell. In this example the Get-ADComputer commandlet is used to retrieve information from the Active Directory and shows all found computer objects in a tree structure mimicking the OU structure in the Active Directory.

 

Special thanks to Paul DeArment from RandomizedHarmony for the contribution. You can also watch a YouTube video about this script here:

https://www.youtube.com/watch?v=pKurlGhMfoQ&feature=youtu.be

 

The following Custom Properties can be configured:

Get-ADComputer Paramater:

SearchBase:

Specifies an Active Directory path to search under.

Example: ou=Enterprise Servers,dc=company,dc=pri

 

Filter:

Specifies a query string that retrieves Active Directory objects.

Example 1: *

Example 2: Name -like "Computer01*"

 

SearchScope:

Specifies the scope of an Active Directory search. The acceptable values for this parameter are:

\r\n\t\t

 

See also: https://docs.microsoft.com/en-us/powershell/module/addsadministration/get-adcomputer?view=win10-ps

 

Connection Object Configuration:

Connection Type:

Specifies which connection type Royal TS should create for the found Actvie Directory computer object.

Example 1: RemoteDesktopConnection

Example 2: TerminalConnection

 

Credential Name:

Specifies the name of the credential for the connection object. If you specify "?" (without the quotes), Royal TS will prompt for the credential.

 

Extending the Script:

You can extend the script to inlcude more configuration settings or use a different credential mode. Feel free to adapt this dynamic folder, extend it, include additional custom properties and documentation, upload it to our github repository.

 

See also: https://www.royalapplications.com/go/kb-all-royaljson

\r\n\r\n","CustomProperties":[{"Name":"Get-ADComputer Parameters","Type":"Header","Value":""},{"Name":"SearchBase","Type":"Text","Value":"ou=Enterprise Servers,dc=company,dc=pri"},{"Name":"Filter","Type":"Text","Value":"*"},{"Name":"SearchScope","Type":"Text","Value":"subtree"},{"Name":"Connection Object Configuration","Type":"Header","Value":""},{"Name":"Connection Type","Type":"Text","Value":"RemoteDesktopConnection"},{"Name":"Credential Name","Type":"Text","Value":"?"}],"ScriptInterpreter":"powershell","DynamicCredentialScriptInterpreter":"json","Script":"Import-Module ActiveDirectory\r\n[System.Collections.ArrayList]$array = @()\r\nforeach ($computer in Get-ADComputer -SearchBase \"$CustomProperty.SearchBase$\" -Filter '$CustomProperty.Filter$' -SearchScope $CustomProperty.SearchScope$ -Properties canonicalname)\r\n{\r\n\t$array.add((\r\n\t\t\tNew-Object -TypeName System.Management.Automation.PSObject -Property @{\r\n\t\t\t\t\"Type\" = \"$CustomProperty.ConnectionType$\";\r\n\t\t\t\t\"Name\" = $computer.name;\r\n\t\t\t\t\"ComputerName\" = $computer.name;\r\n\t\t\t\t\"credentialName\" = \"$CustomProperty.CredentialName$\";\r\n\t\t\t\t\"Path\" = $computer.canonicalname.replace(\"/$($computer.name)\", \"\")\r\n\t\t\t}\r\n\t\t)) | Out-Null\r\n}\r\n$array = $array | Sort-Object -Property path\r\n$hash = @{ }\r\n$hash.add(\"Objects\", $array)\r\n\r\n$hash | ConvertTo-Json"}]} \ No newline at end of file diff --git a/Dynamic Folder/Active Directory/Basic Active Directory (Windows PowerShell).rdfx b/Dynamic Folder/Active Directory/Basic Active Directory (Windows PowerShell).rdfx new file mode 100644 index 0000000..570b8cf --- /dev/null +++ b/Dynamic Folder/Active Directory/Basic Active Directory (Windows PowerShell).rdfx @@ -0,0 +1,166 @@ + + Dynamic Folder Export + + + DynamicFolder + Basic Active Directory (Windows PowerShell) + In this example the Get-ADComputer commandlet is used to retrieve information from the Active Directory and shows all found computer objects in a tree structure mimicking the OU structure in the Active Directory. + + + +

Dynamic Folder for Basic Active Directory Synchronization

+ +

 

+ +

Version: 1.0

+ +

Author: Paul DeArment, Royal Applications

+ +

 

+ +

This is a very basic dynamic folder example for Windows using PowerShell. In this example the Get-ADComputer commandlet is used to retrieve information from the Active Directory and shows all found computer objects in a tree structure mimicking the OU structure in the Active Directory.

+ +

 

+ +

Special thanks to Paul DeArment from RandomizedHarmony for the contribution. You can also watch a YouTube video about this script here:

+ +

https://www.youtube.com/watch?v=pKurlGhMfoQ&feature=youtu.be

+ +

 

+ +

The following Custom Properties can be configured:

+ +

Get-ADComputer Paramater:

+ +

SearchBase:

+ +

Specifies an Active Directory path to search under.

+ +

Example: ou=Enterprise Servers,dc=company,dc=pri

+ +

 

+ +

Filter:

+ +

Specifies a query string that retrieves Active Directory objects.

+ +

Example 1: *

+ +

Example 2: Name -like "Computer01*"

+ +

 

+ +

SearchScope:

+ +

Specifies the scope of an Active Directory search. The acceptable values for this parameter are:

+ +
    +
  • Base or 0
  • +
  • OneLevel or 1
  • +
  • Subtree or 2
  • +
+ +

 

+ +

See also: https://docs.microsoft.com/en-us/powershell/module/addsadministration/get-adcomputer?view=win10-ps

+ +

 

+ +

Connection Object Configuration:

+ +

Connection Type:

+ +

Specifies which connection type Royal TS should create for the found Actvie Directory computer object.

+ +

Example 1: RemoteDesktopConnection

+ +

Example 2: TerminalConnection

+ +

 

+ +

Credential Name:

+ +

Specifies the name of the credential for the connection object. If you specify "?" (without the quotes), Royal TS will prompt for the credential.

+ +

 

+ +

Extending the Script:

+ +

You can extend the script to inlcude more configuration settings or use a different credential mode. Feel free to adapt this dynamic folder, extend it, include additional custom properties and documentation, upload it to our github repository.

+ +

 

+ +

See also: https://www.royalapplications.com/go/kb-all-royaljson

+]]>
+ + + Get-ADComputer Parameters + Header + + + + SearchBase + Text + TODO + + + Filter + Text + TODO + + + SearchScope + Text + TODO + + + Connection Object Configuration + Header + + + + Connection Type + Text + TODO + + + Credential Name + Text + TODO + + + powershell + + json + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file From db73bfdc30de12d4e28acae00883420c731f839c Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 14:21:17 +0100 Subject: [PATCH 02/13] [Refactor] Transform all AWS EC2 scripts --- .../EC2/AWS EC2 (Python).rdfe | 22 --- .../EC2/AWS EC2 (Python).rdfx | 131 ++++++++++++++++++ .../EC2/AWS EC2 SSM (Python).rdfe | 20 --- .../EC2/AWS EC2 SSM (Python).rdfx | 106 ++++++++++++++ 4 files changed, 237 insertions(+), 42 deletions(-) delete mode 100644 Dynamic Folder/Amazon Web Services/EC2/AWS EC2 (Python).rdfe create mode 100644 Dynamic Folder/Amazon Web Services/EC2/AWS EC2 (Python).rdfx delete mode 100644 Dynamic Folder/Amazon Web Services/EC2/AWS EC2 SSM (Python).rdfe create mode 100644 Dynamic Folder/Amazon Web Services/EC2/AWS EC2 SSM (Python).rdfx diff --git a/Dynamic Folder/Amazon Web Services/EC2/AWS EC2 (Python).rdfe b/Dynamic Folder/Amazon Web Services/EC2/AWS EC2 (Python).rdfe deleted file mode 100644 index d556b84..0000000 --- a/Dynamic Folder/Amazon Web Services/EC2/AWS EC2 (Python).rdfe +++ /dev/null @@ -1,22 +0,0 @@ -{ - "Name": "Dynamic Folder Export", - "Objects": [ - { - "Type": "DynamicFolder", - "Name": "AWS EC2 (Python)", - "Description": "This Dynamic Folder sample for AWS EC2 supports grabbing all EC2 instances of a specified region.", - "Notes": "

Dynamic Folder sample for Amazon Web Services (AWS) EC2

\n\n

Version: 1.0.1
\nAuthor: Royal Applications

\n\n

This Dynamic Folder sample for AWS EC2 supports grabbing all EC2 instances of a specified region.

\n\n

Prerequisites

\n\n\n\n

Setup

\n\n\n\n

Notes

\n\n\n", - "CustomProperties": [ - { - "Name": "Region", - "Type": "Text", - "Value": "TODO" - } - ], - "ScriptInterpreter": "python", - "DynamicCredentialScriptInterpreter": "json", - "DynamicCredentialScript": "{\n\t\"Username\": \"user\",\n\t\"Password\": \"pass\"\n}", - "Script": "import subprocess\nimport json\n\ndef get_instances(region = \"\"):\n\tcmd = \"aws ec2 describe-instances --output json\"\n\n\tif region != \"\":\n\t\tcmd += \" --region \" + region\n\n\taws = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)\n\t(response_json, err) = aws.communicate()\n\texit_code = aws.wait()\n\n\tresponse = json.loads(response_json)\n\n\tconnections = [ ]\n\n\tfor reservation in response.get(\"Reservations\", None):\n\t\tfor instance in reservation.get(\"Instances\", None):\n\t\t\tinstance_id = instance.get(\"InstanceId\", \"\")\n\t\t\tplatform = instance.get(\"Platform\", \"\")\n\n\t\t\tis_windows = platform.lower() == \"windows\"\n\t\t\tusername = \"Administrator\" if is_windows else \"ec2-user\"\n\n\t\t\tpublic_ip_address = instance.get(\"PublicIpAddress\", \"\")\n\t\t\tpublic_hostname = instance.get(\"PublicDnsName\", \"\")\n\n\t\t\tprivate_ip_address = instance.get(\"PrivateIpAddress\", \"\")\n\t\t\tprivate_hostname = instance.get(\"PrivateDnsName\", \"\")\n\n\t\t\ttags = instance.get(\"Tags\")\n\t\t\tname = instance_id\n\n\t\t\tif tags is not None:\n\t\t\t\tfor tag in tags:\n\t\t\t\t\tif tag.get(\"Key\", \"\").lower() == \"name\":\n\t\t\t\t\t\ttagValue = tag.get(\"Value\", \"\")\n\n\t\t\t\t\t\tif tagValue.lower() != \"\":\n\t\t\t\t\t\t\tname = tagValue\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak\n\n\t\t\tcomputer_name = public_hostname\n\n\t\t\tif computer_name == \"\":\n\t\t\t\tcomputer_name = public_ip_address\n\n\t\t\tif computer_name == \"\":\n\t\t\t\tcomputer_name = private_hostname\n\n\t\t\tif computer_name == \"\":\n\t\t\t\tcomputer_name = private_ip_address\n\n\t\t\tconnection = { }\n\n\t\t\tif not is_windows:\n\t\t\t\tconnection[\"Type\"] = \"TerminalConnection\"\n\t\t\t\tconnection[\"TerminalConnectionType\"] = \"SSH\"\n\t\t\telse:\n\t\t\t\tconnection[\"Type\"] = \"RemoteDesktopConnection\"\n\n\t\t\tconnection[\"ID\"] = instance_id\n\t\t\tconnection[\"Name\"] = name\n\t\t\tconnection[\"ComputerName\"] = computer_name\n\t\t\tconnection[\"Username\"] = username\n\n\t\t\tconnections.append(connection)\n\n\tstore = {\n\t\t\"Objects\": connections\n\t}\n\n\tstore_json = json.dumps(store)\n\n\treturn store_json\n\nprint(get_instances(\"$CustomProperty.Region$\"))" - } - ] -} \ No newline at end of file diff --git a/Dynamic Folder/Amazon Web Services/EC2/AWS EC2 (Python).rdfx b/Dynamic Folder/Amazon Web Services/EC2/AWS EC2 (Python).rdfx new file mode 100644 index 0000000..59abfc6 --- /dev/null +++ b/Dynamic Folder/Amazon Web Services/EC2/AWS EC2 (Python).rdfx @@ -0,0 +1,131 @@ + + Dynamic Folder Export + + + DynamicFolder + AWS EC2 (Python) + This Dynamic Folder sample for AWS EC2 supports grabbing all EC2 instances of a specified region. + Dynamic Folder sample for Amazon Web Services (AWS) EC2 + +

Version: 1.0.1
+Author: Royal Applications

+ +

This Dynamic Folder sample for AWS EC2 supports grabbing all EC2 instances of a specified region.

+ +

Prerequisites

+ +
    +
  • AWS Command Line Interface (CLI) needs to be installed and configured.
  • +
+ +

Setup

+ +
    +
  • Enter the region that you want to grab instances from in the "Region" field in the "Custom Properties" section or leave it as an empty string if you configured the AWS CLI with a default region.
  • +
+ +

Notes

+ +
    +
  • While the provided script sets the username of created connections, the password will always be empty. There are multiple different ways to solve this. For instance, you could assign a credential to this dynamic folder and change the script to reference credentials from parent folder. Alternatively, you may also just use "Connect with Options - Prompt for Credentials" when establishing a connection.
  • +
+]]>
+ + + Region + Text + TODO + + + python + + json + + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file diff --git a/Dynamic Folder/Amazon Web Services/EC2/AWS EC2 SSM (Python).rdfe b/Dynamic Folder/Amazon Web Services/EC2/AWS EC2 SSM (Python).rdfe deleted file mode 100644 index 9f8a3fc..0000000 --- a/Dynamic Folder/Amazon Web Services/EC2/AWS EC2 SSM (Python).rdfe +++ /dev/null @@ -1,20 +0,0 @@ -{ - "Name": "Dynamic Folder Export", - "Objects": [ - { - "Type": "DynamicFolder", - "Name": "AWS EC2 SSM (Python)", - "Description": "This Dynamic Folder sample for AWS SSM EC2 supports grabbing all EC2 instances of a specified region managed by AWS Systems Manager.", - "Notes": "

Dynamic Folder sample for Amazon Web Services (AWS) EC2 managed by SSM

\n\n

Version: 1.0.0
\nAuthor: Chrysostomos Galatoulas

\n\n

This Dynamic Folder sample for AWS EC2 SSM supports grabbing all EC2 instances of a specified region managed by SSM. The script creates terminal connections with custom commands which is a feature only Royal TSX (for macOS) supports at the moment. That means this script currently only works on macOS and does NOT support Windows.

\n\n

Prerequisites

\n\n\n\n

Setup

\n\n\n\n

Notes

\n\n\n", - "CustomProperties": [ - { - "Name": "Region", - "Type": "Text", - "Value": "us-east-1" - } - ], - "ScriptInterpreter": "python", - "Script": "import subprocess\nimport json\n\ndef get_instances(region = \"\"):\n\tcmd = \"aws ssm describe-instance-information --output json\"\n\n\tif region != \"\":\n\t\tcmd += \" --region \" + region\n\n\taws = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)\n\t(response_json, err) = aws.communicate()\n\texit_code = aws.wait()\n\n\tresponse = json.loads(response_json)\n\n\tconnections = [ ]\n\n\tfor instance in response.get(\"InstanceInformationList\", None):\n\t\tinstance_id = instance.get(\"InstanceId\", \"\")\n\t\tplatform = instance.get(\"PlatformType\", \"\")\n\n\t\tis_windows = platform.lower() == \"windows\"\n\n\t\tcomputer_name = instance.get(\"ComputerName\", \"\")\n\t\tprivate_ip_address = instance.get(\"IPAddress\", \"\")\n\n\t\tname = instance_id\n\n\t\tconnection = { }\n\t\tif not is_windows:\n\t\t\tconnection[\"Type\"] = \"TerminalConnection\"\n\t\t\tconnection[\"TerminalConnectionType\"] = \"CustomTerminal\"\n\t\telse:\n\t\t\tconnection[\"Type\"] = \"RemoteDesktopConnection\"\n\n\t\tconnection[\"ID\"] = instance_id\n\t\tconnection[\"Name\"] = computer_name\n\t\tconnection[\"ComputerName\"] = computer_name\n\n\t\tconnection[\"CustomCommand\"] = f\"aws ssm start-session --target {instance_id}\"\t\t\n\t\t\n\t\t\n\t\tconnection[\"Properties\"] = {}\n\t\tconnection[\"Properties\"][\"RunInsideLoginShell\"] = True\n\t\t\n\t\t\n\t\tconnections.append(connection)\n\n\tstore = {\n\t\t\"Objects\": connections\n\t}\n\n\tstore_json = json.dumps(store)\n\n\treturn store_json\n\t\nprint(get_instances(\"$CustomProperty.Region$\"))\n" - } - ] -} diff --git a/Dynamic Folder/Amazon Web Services/EC2/AWS EC2 SSM (Python).rdfx b/Dynamic Folder/Amazon Web Services/EC2/AWS EC2 SSM (Python).rdfx new file mode 100644 index 0000000..d387e32 --- /dev/null +++ b/Dynamic Folder/Amazon Web Services/EC2/AWS EC2 SSM (Python).rdfx @@ -0,0 +1,106 @@ + + Dynamic Folder Export + + + DynamicFolder + AWS EC2 SSM (Python) + This Dynamic Folder sample for AWS SSM EC2 supports grabbing all EC2 instances of a specified region managed by AWS Systems Manager. + Dynamic Folder sample for Amazon Web Services (AWS) EC2 managed by SSM + +

Version: 1.0.0
+Author: Chrysostomos Galatoulas

+ +

This Dynamic Folder sample for AWS EC2 SSM supports grabbing all EC2 instances of a specified region managed by SSM. The script creates terminal connections with custom commands which is a feature only Royal TSX (for macOS) supports at the moment. That means this script currently only works on macOS and does NOT support Windows.

+ +

Prerequisites

+ +
    +
  • AWS Command Line Interface (CLI) needs to be installed and configured.
  • +
+ +

Setup

+ +
    +
  • Enter the region that you want to grab instances from in the "Region" field in the "Custom Properties" section or leave it as an empty string if you configured the AWS CLI with a default region.
  • +
+ +

Notes

+ +
    +
  • You can append the --profile option on AWS cli commands to use a configured profile instead of a default.
  • +
+]]>
+ + + Region + Text + TODO + + + python + + json + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file From 5c14527f025b80e9ff09c9a074f5420485f13578 Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 14:30:45 +0100 Subject: [PATCH 03/13] [Refactor] Transform all CSV scripts --- Dynamic Folder/CSV/CSV (PowerShell).rdfe | 1 - Dynamic Folder/CSV/CSV (PowerShell).rdfx | 65 +++++++++++++++++++++ Dynamic Folder/CSV/CSV (Python).rdfe | 1 - Dynamic Folder/CSV/CSV (Python).rdfx | 72 ++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 2 deletions(-) delete mode 100644 Dynamic Folder/CSV/CSV (PowerShell).rdfe create mode 100644 Dynamic Folder/CSV/CSV (PowerShell).rdfx delete mode 100644 Dynamic Folder/CSV/CSV (Python).rdfe create mode 100644 Dynamic Folder/CSV/CSV (Python).rdfx diff --git a/Dynamic Folder/CSV/CSV (PowerShell).rdfe b/Dynamic Folder/CSV/CSV (PowerShell).rdfe deleted file mode 100644 index 17e899d..0000000 --- a/Dynamic Folder/CSV/CSV (PowerShell).rdfe +++ /dev/null @@ -1 +0,0 @@ -{"Name":"Dynamic Folder Export","Objects":[{"Type":"DynamicFolder","Name":"CSV (PowerShell)","Description": "This Dynamic Folder sample for CSV files allows you to import connections from a CSV file.","Notes":"

Dynamic Folder sample for CSV

\n\n

Version: 1.0
\nAuthor: Royal Applications

\n\n

This Dynamic Folder sample for CSV files allows you to import connections from a CSV file.

\n\n

Setup

\n\n
    \n\t
  • Enter the path to your CSV file in the "CSV Path" field in the "Custom Properties" section.
  • \n
\n","CustomProperties":[{"Name":"CSV Path","Type":"URL","Value":"TODO"}],"ScriptInterpreter":"powershell","DynamicCredentialScriptInterpreter":"json","Script":"$ErrorActionPreference = \"Stop\"\n\n$computers = Import-Csv \"$CustomProperty.CSVPath$\"\n\n$connections = @()\n\nForEach ($computer in $computers) {\n $name = $computer.Name\n $computerName = $computer.ComputerName\n $username = $computer.Username\n $password = $computer.Password\n\n $connection = New-Object pscustomobject -Property @{\n \"Type\" = \"TerminalConnection\";\n \"TerminalConnectionType\" = \"SSH\";\n \"Name\" = $name;\n \"ComputerName\" = $computerName;\n \"Username\" = $username;\n \"Password\" = $password;\n }\n\n $connections += $connection\n}\n\n@{\n Objects = $connections\n} |\nConvertTo-Json -Depth 100 |\nWrite-Host"}]} \ No newline at end of file diff --git a/Dynamic Folder/CSV/CSV (PowerShell).rdfx b/Dynamic Folder/CSV/CSV (PowerShell).rdfx new file mode 100644 index 0000000..632e5d0 --- /dev/null +++ b/Dynamic Folder/CSV/CSV (PowerShell).rdfx @@ -0,0 +1,65 @@ + + Dynamic Folder Export + + + DynamicFolder + CSV (PowerShell) + This Dynamic Folder sample for CSV files allows you to import connections from a CSV file. + Dynamic Folder sample for CSV + +

Version: 1.0
+Author: Royal Applications

+ +

This Dynamic Folder sample for CSV files allows you to import connections from a CSV file.

+ +

Setup

+ +
    +
  • Enter the path to your CSV file in the "CSV Path" field in the "Custom Properties" section.
  • +
+]]>
+ + + CSV Path + URL + TODO + + + powershell + + json + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file diff --git a/Dynamic Folder/CSV/CSV (Python).rdfe b/Dynamic Folder/CSV/CSV (Python).rdfe deleted file mode 100644 index 1b0595e..0000000 --- a/Dynamic Folder/CSV/CSV (Python).rdfe +++ /dev/null @@ -1 +0,0 @@ -{"Name":"Dynamic Folder Export","Objects":[{"Type":"DynamicFolder","Name":"CSV (Python)","Description": "This Dynamic Folder sample for CSV files allows you to import connections from a CSV file.","Notes":"

Dynamic Folder sample for CSV

\n\n

Version: 1.0
\nAuthor: Royal Applications

\n\n

This Dynamic Folder sample for CSV files allows you to import connections from a CSV file.

\n\n

Setup

\n\n
    \n\t
  • Enter the path to your CSV file in the "CSV Path" field in the "Custom Properties" section.
  • \n
\n","CustomProperties":[{"Name":"CSV Path","Type":"URL","Value":"TODO"}],"ScriptInterpreter":"python","DynamicCredentialScriptInterpreter":"json","Script":"import os\nimport csv\nimport json\n\ndef get_entries(csv_path):\n csvfile = open(os.path.expanduser(csv_path))\n reader = csv.DictReader(csvfile)\n\n connections = []\n\n for row in reader:\n name = row[\"Name\"]\n computerName = row[\"ComputerName\"]\n username = row[\"Username\"]\n password = row[\"Password\"]\n\n connection = {\n \"Type\": \"TerminalConnection\",\n \"TerminalConnectionType\": \"SSH\",\n \"Name\": name,\n \"ComputerName\": computerName,\n \"Username\": username,\n \"Password\": password\n }\n\n connections.append(connection)\n\n store = {\n \"Objects\": connections\n }\n\n store_json = json.dumps(store)\n\n return store_json\n\nprint(get_entries(\"$CustomProperty.CSVPath$\"))"}]} \ No newline at end of file diff --git a/Dynamic Folder/CSV/CSV (Python).rdfx b/Dynamic Folder/CSV/CSV (Python).rdfx new file mode 100644 index 0000000..4ef5690 --- /dev/null +++ b/Dynamic Folder/CSV/CSV (Python).rdfx @@ -0,0 +1,72 @@ + + Dynamic Folder Export + + + DynamicFolder + CSV (Python) + This Dynamic Folder sample for CSV files allows you to import connections from a CSV file. + Dynamic Folder sample for CSV + +

Version: 1.0
+Author: Royal Applications

+ +

This Dynamic Folder sample for CSV files allows you to import connections from a CSV file.

+ +

Setup

+ +
    +
  • Enter the path to your CSV file in the "CSV Path" field in the "Custom Properties" section.
  • +
+]]>
+ + + CSV Path + URL + TODO + + + python + + json + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file From 69fef3c48b95af15f1ae11b1828d01f9a85c86a0 Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 14:31:57 +0100 Subject: [PATCH 04/13] [Refactor] Transform all Foreman scripts --- Dynamic Folder/Foreman/Foreman (PHP).rdfe | 25 ---- Dynamic Folder/Foreman/Foreman (PHP).rdfx | 150 ++++++++++++++++++++++ 2 files changed, 150 insertions(+), 25 deletions(-) delete mode 100644 Dynamic Folder/Foreman/Foreman (PHP).rdfe create mode 100644 Dynamic Folder/Foreman/Foreman (PHP).rdfx diff --git a/Dynamic Folder/Foreman/Foreman (PHP).rdfe b/Dynamic Folder/Foreman/Foreman (PHP).rdfe deleted file mode 100644 index 54dcfa2..0000000 --- a/Dynamic Folder/Foreman/Foreman (PHP).rdfe +++ /dev/null @@ -1,25 +0,0 @@ -{ - "Name":"Dynamic Folder Export", - "Objects":[ - { - "Type":"DynamicFolder", - "Name":"Foreman", - "Description":"This Dynamic Folder script will list all your servers from your Foreman Instance", - "Notes":"\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t

\r\n\t\t\tDynamic Folder support for Foreman

\r\n\t\t

Version: 1.0
Author: Daniel Rieper

This Dynamic Folder script will list all your servers from your Foreman Instance.

Prerequisites

\r\n\t\t

Setup

    \r\n\t\t\t
  • Enter your Foreman URL under the Custom Properties section of the Dynamic Folder. There's a property "Foreman URL", which is used to store the URL of your Instance.
  • Enter your Foreman Credentials under the Credentials section of the Dynamic Folder.
\r\n\t\t

 

    \r\n\t\t\t
  • If you Prefer a Connection over IP instead of DNS set the property "Connect by IP" to Yes.
\r\n\t\t

Notes

    \r\n\t\t\t
  • All Servers with Windows are configured as RDP all other as SSH.
\r\n\t\t

 

\r\n\r\n", - "CustomProperties":[ - { - "Name":"Foreman URL", - "Type":"URL", - "Value":"TODO" - }, - { - "Name":"Connect by IP", - "Type":"YesNo", - "Value":"False" - } - ], - "ScriptInterpreter":"php", - "Script":"function sendError($text) {\r\n\tfwrite(STDERR, \"ERROR: \".$text);\r\n\texit;\r\n}\r\n\r\n$host = '$CustomProperty.ForemanURL$';\r\n$user = '$EffectiveUsername$';\r\n$pass = '$EffectivePassword$';\r\n$preferIP = strtolower('$CustomProperty.ConnectbyIP$') == 'yes';\r\n\r\nif(empty($host) || $host=='TODO') sendError('Set Foreman URL in Custom-Propertys');\r\nif(empty($user) || empty($pass)) sendError('No Credentials configured');\r\n\r\n$ch = curl_init($host.'/api/hosts');\r\ncurl_setopt($ch, CURLOPT_USERPWD, \"{$user}:{$pass}\");\r\ncurl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);\r\ncurl_setopt($ch, CURLOPT_HEADER, false);\r\ncurl_setopt($ch, CURLOPT_TIMEOUT, 30);\r\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);\r\ncurl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);\r\ncurl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\r\n$return = curl_exec($ch);\r\ncurl_close($ch);\r\n\r\nif(empty($return)) sendError(\"Can't connect to Foreman\"); \r\n$hosts = json_decode($return);\r\nif(empty($hosts)) sendError(\"Invalid Response from Foreman\"); \r\nif(!empty($hosts->error)) sendError($hosts->error->message); \r\nif(count((array)$hosts->results) == 0) sendError(\"No Hosts found\"); \r\n\r\n$folders = array();\r\nforeach($hosts->results as $host)\r\n{\r\n\tif(!isset($folders[$host->location_name])) $folders[$host->location_name] = array();\r\n\t$e = &$folders[$host->location_name][];\r\n\r\n\t$e['Name'] = $host->name;\r\n\tif($preferIP)\r\n\t{\r\n\t\tif(!empty($host->ip)) $e['ComputerName'] = $host->ip;\r\n\t\telse if(!empty($host->ip6)) $e['ComputerName'] = $host->ip6;\r\n\t}\r\n\tif(empty($e['ComputerName'])) $e['ComputerName'] = $host->certname;\r\n\t$e['MACAddress'] = $host->mac;\r\n\r\n\t$desc = '';\r\n\tif(!empty($host->ip)) $desc.=\"IPv4: {$host->ip}\\r\\n\";\r\n\tif(!empty($host->ip6)) $desc.=\"IPv6: {$host->ip6}\\r\\n\";\r\n\tif(!empty($host->operatingsystem_name)) $desc.=\"OS: {$host->operatingsystem_name}\\r\\n\";\r\n\tif(!empty($host->compute_resource_name)) $desc.=\"VM HOST: {$host->compute_resource_name}\\r\\n\";\r\n\telse if(!empty($host->model_name)) $desc.=\"Model: {$host->model_name}\\r\\n\";\r\n\t\r\n\tif(!empty($desc)) $e['Description'] = \"\\r\\n\".$desc;\r\n\r\n\tif(strpos($host->operatingsystem_name, 'windows') !== FALSE)\r\n\t{\r\n\t\t$e['Type'] = 'RemoteDesktopConnection';\r\n\t\t$e['IconName'] ='/Flat/Hardware/Platform OS Windows';\r\n\t} else {\r\n\t\t$e['Type'] = 'TerminalConnection';\r\n\t\t$e['TerminalConnectionType'] = 'SSH';\r\n\t\t$e['IconName'] ='/Flat/Hardware/Platform OS Linux';\r\n\t}\r\n}\r\n\r\n$ret = array();\r\nforeach($folders as $foldername => $entrys)\r\n{\r\n\t$e = &$ret[];\r\n\t$e['Name'] = $foldername;\r\n\t$e['Type'] = 'Folder';\r\n\t$e['Objects'] = $entrys;\r\n}\r\n\r\n$json = json_encode(array( \"Objects\" => $ret ));\r\necho $json;" - } - ] -} diff --git a/Dynamic Folder/Foreman/Foreman (PHP).rdfx b/Dynamic Folder/Foreman/Foreman (PHP).rdfx new file mode 100644 index 0000000..0559ca1 --- /dev/null +++ b/Dynamic Folder/Foreman/Foreman (PHP).rdfx @@ -0,0 +1,150 @@ + + Dynamic Folder Export + + + DynamicFolder + Foreman (PHP) + This Dynamic Folder script will list all your servers from your Foreman Instance + + + +

Dynamic Folder support for Foreman

+ +

Version: 1.0
+Author: Daniel Rieper

+ +

This Dynamic Folder script will list all your servers from your Foreman Instance.

+ +

Prerequisites

+ + + +

Setup

+ +
    +
  • Enter your Foreman URL under the Custom Properties section of the Dynamic Folder. There's a property "Foreman URL", which is used to store the URL of your Instance.
  • +
  • Enter your Foreman Credentials under the Credentials section of the Dynamic Folder.
  • +
+ +

 

+ +
    +
  • If you Prefer a Connection over IP instead of DNS set the property "Connect by IP" to Yes.
  • +
+ +

Notes

+ +
    +
  • All Servers with Windows are configured as RDP all other as SSH.
  • +
+ +

 

+]]>
+ + + Foreman URL + URL + TODO + + + Connect by IP + YesNo + False + + + php + + json + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file From f7f23574346006599a3e6c75a4065ef6ebfe695a Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 14:33:07 +0100 Subject: [PATCH 05/13] [Refactor] Transform all Hetzner scripts --- .../Hetzner Cloud/Hetzner Cloud (Python).rdfe | 1 - .../Hetzner Cloud/Hetzner Cloud (Python).rdfx | 104 ++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) delete mode 100644 Dynamic Folder/Hetzner/Hetzner Cloud/Hetzner Cloud (Python).rdfe create mode 100644 Dynamic Folder/Hetzner/Hetzner Cloud/Hetzner Cloud (Python).rdfx diff --git a/Dynamic Folder/Hetzner/Hetzner Cloud/Hetzner Cloud (Python).rdfe b/Dynamic Folder/Hetzner/Hetzner Cloud/Hetzner Cloud (Python).rdfe deleted file mode 100644 index a548800..0000000 --- a/Dynamic Folder/Hetzner/Hetzner Cloud/Hetzner Cloud (Python).rdfe +++ /dev/null @@ -1 +0,0 @@ -{"Name":"Dynamic Folder Export","Objects":[{"Type":"DynamicFolder","Name":"Hetzner Cloud (Python)","Description": "This Dynamic Folder script will list all your servers for the given API Key of the Hetzner Cloud.","Notes":"\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t

\r\n\t\t\tDynamic Folder support for Hetzner Cloud

\r\n\t\t

Version: 1.0
Author: Max Schmitt

This Dynamic Folder script will list all your servers for the given API Key of the Hetzner Cloud.

Prerequisites

\r\n\t\t

\r\n\t\t\tSetup

\r\n\t\t
    \r\n\t\t\t
  • Enter your API Key, which you've got from the Hetzner Cloud Console and place it under the Custom Properties section of the Dynamic Folder. There's a property"API Key", which is used to store the API Key of your project.
\r\n\t\t

\r\n\t\t\tNotes

\r\n\t\t
    \r\n\t\t\t
  • Per default the auto created servers are setup to inherit their credentials from the Dynamic Folder. So if you set their the credentials all underlying servers will use them.
\r\n\t\r\n\r\n","CustomProperties":[{"Name":"API Key","Type":"Protected","Value":"TODO"}],"ScriptInterpreter":"python","DynamicCredentialScriptInterpreter":"json","Script":"import subprocess\r\nimport json\r\nimport os\r\nimport re\r\nimport sys\r\n\r\n# log_error will write the error to the stderr, so that Royal TS will display it.\r\n\r\n\r\ndef log_error(err):\r\n print(\"error: {}\".format(err.strip()), file=sys.stderr)\r\n exit(1)\r\n\r\n\r\ndef get_instances(api_key):\r\n os.environ[\"HCLOUD_TOKEN\"] = api_key\r\n cmd = \"hcloud\"\r\n store = {\r\n \"Objects\": []\r\n }\r\n # get servers\r\n server_list_process = subprocess.Popen(\r\n \"{} server list -o columns=id,name,ipv4 -o noheader\".format(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE)\r\n (stdout, stderr) = server_list_process.communicate()\r\n exit_code = server_list_process.wait()\r\n # check if hcloud returned a successful status code != 0\r\n if exit_code != 0:\r\n log_error(\"could not get server list: {}\".format(stderr.decode()))\r\n # loop over the returned servers and build the royal ts JSON\r\n for line in stdout.decode().strip().splitlines():\r\n values = re.findall(r\"[^ ]+\", line)\r\n store[\"Objects\"].append({\r\n \"ID\": values[0],\r\n \"Name\": values[1],\r\n \"ComputerName\": values[2],\r\n \"Username\": \"root\",\r\n \"Type\": \"TerminalConnection\",\r\n \"TerminalConnectionType\": \"SSH\",\r\n \"CredentialsFromParent\": True\r\n })\r\n return json.dumps(store)\r\n\r\n\r\nprint(get_instances(\"$CustomProperty.APIKey$\"))\r\n"}]} diff --git a/Dynamic Folder/Hetzner/Hetzner Cloud/Hetzner Cloud (Python).rdfx b/Dynamic Folder/Hetzner/Hetzner Cloud/Hetzner Cloud (Python).rdfx new file mode 100644 index 0000000..b0372d8 --- /dev/null +++ b/Dynamic Folder/Hetzner/Hetzner Cloud/Hetzner Cloud (Python).rdfx @@ -0,0 +1,104 @@ + + Dynamic Folder Export + + + DynamicFolder + Hetzner Cloud (Python) + This Dynamic Folder script will list all your servers for the given API Key of the Hetzner Cloud. + + + +

Dynamic Folder support for Hetzner Cloud

+ +

Version: 1.0
+Author: Max Schmitt

+ +

This Dynamic Folder script will list all your servers for the given API Key of the Hetzner Cloud.

+ +

Prerequisites

+ + + +

Setup

+ +
    +
  • Enter your API Key, which you've got from the Hetzner Cloud Console and place it under the Custom Properties section of the Dynamic Folder. There's a property"API Key", which is used to store the API Key of your project.
  • +
+ +

Notes

+ +
    +
  • Per default the auto created servers are setup to inherit their credentials from the Dynamic Folder. So if you set their the credentials all underlying servers will use them.
  • +
+]]>
+ + + API Key + Protected + TODO + + + python + + json + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file From b7d95704beb48bb22d3059b39e4bd041fa268072 Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 14:49:43 +0100 Subject: [PATCH 06/13] [Refactor] Transform all IBM scripts --- .../Softlayer/Softlayer Servers (Python).rdfe | 22 ---- .../Softlayer/Softlayer Servers (Python).rdfx | 119 ++++++++++++++++++ 2 files changed, 119 insertions(+), 22 deletions(-) delete mode 100644 Dynamic Folder/IBM/Softlayer/Softlayer Servers (Python).rdfe create mode 100644 Dynamic Folder/IBM/Softlayer/Softlayer Servers (Python).rdfx diff --git a/Dynamic Folder/IBM/Softlayer/Softlayer Servers (Python).rdfe b/Dynamic Folder/IBM/Softlayer/Softlayer Servers (Python).rdfe deleted file mode 100644 index 843fc8a..0000000 --- a/Dynamic Folder/IBM/Softlayer/Softlayer Servers (Python).rdfe +++ /dev/null @@ -1,22 +0,0 @@ -{ - "Name": "Dynamic Folder Export", - "Objects": [ - { - "Type": "DynamicFolder", - "Name": "Softlayer Servers (Python)", - "Description": "This Dynamic Folder sample for IBM Softlayer supports grabbing all virtual servers of a specified datacenter.", - "Notes": "

Dynamic Folder sample for IBM Softlayer Virtual Server

\n\n

Version: 1.0
\nAuthor: Royal Applications, Matt Warren

\n\n

This Dynamic Folder sample for IBM Softlayer supports grabbing all virtual servers of a specified datacenter.

\n\n

Prerequisites

\n\n\n\n

Setup

\n\n
    \n\t
  • Enter the datacenter that you want to grab instances from in the "Datacenter" field in the "Custom Properties" section or leave it as an empty string if you configured the SLCLI with a default datacenter.
  • \n\t
  • Depends on a SLCLI config file for username and password/key.
  • \n
\n\n

Notes

\n\n
    \n\t
  • The provided script sets SSH connections to "Use credentials from parent folder" and sets RDP connections to "Specify a credential name" There are multiple different ways to manage credentials with Royal. Alternatively, you may also just use "Connect with Options - Prompt for Credentials" when establishing a connection.
  • \n
\n", - "CustomProperties": [ - { - "Name": "Datacenter", - "Type": "Text", - "Value": "tor01" - } - ], - "ScriptInterpreter": "python", - "DynamicCredentialScriptInterpreter": "json", - "DynamicCredentialScript": "{\n\t\"Username\": \"user\",\n\t\"Password\": \"pass\"\n}", - "Script": "import SoftLayer\nimport json\n\n\ndef get_instances(datacenter = \"\"):\n\n client = SoftLayer.Client()\n mgr = SoftLayer.VSManager(client)\n\n connections = [ ]\n\n object_mask = \"mask[globalIdentifier,hostname,operatingSystemReferenceCode,primaryBackendIpAddress]\"\n for instance in mgr.list_instances(datacenter=datacenter, mask=object_mask):\n\n instance_id = instance.get(\"globalIdentifier\", \"\")\n is_windows = instance.get(\"operatingSystemReferenceCode\").partition('_')[0] == \"WIN\"\n\n\n# public_ip_address = instance.get(\"PublicIpAddress\", \"\")\n# public_hostname = instance.get(\"PublicDnsName\", \"\")\n\n private_ip_address = instance.get(\"primaryBackendIpAddress\", \"\")\n private_hostname = instance.get(\"hostname\", \"\")\n name = private_hostname\n\n# Fetching tags on each vs is very time consuming. \n# tags = details.get(\"tagReferences\")\n# tagstring = [ ]\n# for tag in tags:\n# tagstring.append(tag['tag'].get('name'))\n# notes = ' '.join(tagstring)\n \n\n computer_name = private_ip_address\n\n if computer_name == \"\":\n computer_name = public_ip_address\n\n connection = { }\n\n if not is_windows:\n connection[\"Type\"] = \"TerminalConnection\"\n connection[\"TerminalConnectionType\"] = \"SSH\"\n connection['CredentialsFromParent'] = True\n else:\n connection[\"Type\"] = \"RemoteDesktopConnection\"\n connection['CredentialName'] = \"AD_Crendentials\"\n\n connection[\"ID\"] = instance_id\n connection[\"Name\"] = name\n connection[\"ComputerName\"] = computer_name\n# connection['Notes'] = notes\n \n\n connections.append(connection)\n\n store = {\n \"Objects\": connections\n }\n\n store_json = json.dumps(store, indent=2)\n\n return store_json\n\nprint(get_instances(\"$CustomProperty.Datacenter$\"))" - } - ] -} \ No newline at end of file diff --git a/Dynamic Folder/IBM/Softlayer/Softlayer Servers (Python).rdfx b/Dynamic Folder/IBM/Softlayer/Softlayer Servers (Python).rdfx new file mode 100644 index 0000000..284bceb --- /dev/null +++ b/Dynamic Folder/IBM/Softlayer/Softlayer Servers (Python).rdfx @@ -0,0 +1,119 @@ + + Dynamic Folder Export + + + DynamicFolder + Softlayer Servers (Python) + This Dynamic Folder sample for IBM Softlayer supports grabbing all virtual servers of a specified datacenter. + Dynamic Folder sample for IBM Softlayer Virtual Server + +

Version: 1.0
+Author: Royal Applications, Matt Warren

+ +

This Dynamic Folder sample for IBM Softlayer supports grabbing all virtual servers of a specified datacenter.

+ +

Prerequisites

+ + + +

Setup

+ +
    +
  • Enter the datacenter that you want to grab instances from in the "Datacenter" field in the "Custom Properties" section or leave it as an empty string if you configured the SLCLI with a default datacenter.
  • +
  • Depends on a SLCLI config file for username and password/key.
  • +
+ +

Notes

+ +
    +
  • The provided script sets SSH connections to "Use credentials from parent folder" and sets RDP connections to "Specify a credential name" There are multiple different ways to manage credentials with Royal. Alternatively, you may also just use "Connect with Options - Prompt for Credentials" when establishing a connection.
  • +
+]]>
+ + + Datacenter + Text + TODO + + + python + + json + + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file From 9f9721a1842521243858f799e96a445547b37138 Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 14:55:01 +0100 Subject: [PATCH 07/13] [Refactor] Transform all Keeper scripts --- .../Keeper/Keeper (Powershell Core).rdfe | 1 - .../Keeper/Keeper (Powershell Core).rdfx | 110 ++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) delete mode 100644 Dynamic Folder/Keeper/Keeper (Powershell Core).rdfe create mode 100644 Dynamic Folder/Keeper/Keeper (Powershell Core).rdfx diff --git a/Dynamic Folder/Keeper/Keeper (Powershell Core).rdfe b/Dynamic Folder/Keeper/Keeper (Powershell Core).rdfe deleted file mode 100644 index 1d48ae9..0000000 --- a/Dynamic Folder/Keeper/Keeper (Powershell Core).rdfe +++ /dev/null @@ -1 +0,0 @@ -{"Name":"Dynamic Folder Export","Objects":[{"Type":"DynamicFolder","Name":"Keeper (Powershell Core)","Description":"Get dynamic credentials from Keeper Secrets Manager","Notes":"\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t

\r\n\t\t\tKeeper (Powershell) Dynamic Folder

\r\n\t\t

\r\n\t\t\tVersion: 1.0.0
Author
: https://github.com/WillEllis

\r\n\t\t

\r\n\t\t\tHow to use

\r\n\t\t

Ensure you set the RoyalTS script interpreter as Powershell Core. E.g. "C:\\Program Files\\PowerShell\\7\\pwsh.exe"

\r\n\t\t\tCreate a Keeper application

\r\n\t\t

You will need to create an application in Keeper and get a one time access token. Follow the quick start guide here: Keeper Create an Application

\r\n\t\t\tCreate a Keeper application

\r\n\t\t

Setup Keeper Secrets Manager for Powershell (in Powershell core) following this guide Keeper Powershell Plugin - Installation

\r\n\t\t\tConnect Dynamic Folder to Powershell Keeper Vault

\r\n\t\t

\r\n\t\t\tIf you've done the above then you'll have a Powershell Vault in place for Keeper. Simply set the name of the vault and the password (if set) within the custom properties of this Dynamic folder.

\r\n\t\t

 

\r\n\r\n","CustomProperties":[{"Name":"PowerShell Vault Name","Type":"Text","Value":"TODO"},{"Name":"PowerShell Vault Password","Type":"Protected","Value":"TODO"}],"Script":"$ErrorActionPreference = 'Stop'\r\n\r\nif ('$CustomProperty.PowerShellVaultName$' -eq '') {\r\n throw 'Vault Name needed'\r\n}\r\nif ('$CustomProperty.PowerShellVaultPassword$' -eq '') {\r\n throw 'Vault password needed'\r\n}\r\n\r\n$Secure = ConvertTo-SecureString -String '$CustomProperty.PowerShellVaultPassword$' -AsPlainText -Force\r\nUnlock-SecretStore -Password $Secure\r\n\r\n$results = Get-SecretInfo -Vault '$CustomProperty.PowerShellVaultName$'\r\n$credentials = @()\r\nforeach ($item in $results) {\r\n $ID,$name = $item.Name -split ' ',2\r\n $credentials += [pscustomobject]@{\r\n Type = 'DynamicCredential'\r\n Name = $name\r\n Username = ''\r\n Password = ''\r\n ID = $ID\r\n }\r\n}\r\n\r\n$final = [pscustomobject]@{\r\n Objects = ($credentials | Sort-Object Name)\r\n}\r\n$final | ConvertTo-Json -Depth 100 | Write-Output","ScriptInterpreter":"powershell","DynamicCredentialScriptInterpreter":"powershell","DynamicCredentialScript":"$ErrorActionPreference = 'Stop'\r\n\r\nif ('$CustomProperty.PowerShellVaultName$' -eq '') {\r\n throw 'Vault Name needed'\r\n}\r\nif ('$CustomProperty.PowerShellVaultPassword$' -eq '') {\r\n throw 'Vault password needed'\r\n}\r\n\r\n$Secure = ConvertTo-SecureString -String '$CustomProperty.PowerShellVaultPassword$' -AsPlainText -Force\r\nUnlock-SecretStore -Password $Secure\r\n\r\n$results = Get-Secret '$DynamicCredential.EffectiveID$' -AsPlainText\r\n$results | Select-Object @{Name='username';Expression={$_.login}},password | ConvertTo-Json -Depth 100 | Write-Output"}]} diff --git a/Dynamic Folder/Keeper/Keeper (Powershell Core).rdfx b/Dynamic Folder/Keeper/Keeper (Powershell Core).rdfx new file mode 100644 index 0000000..40e4a30 --- /dev/null +++ b/Dynamic Folder/Keeper/Keeper (Powershell Core).rdfx @@ -0,0 +1,110 @@ + + Dynamic Folder Export + + + DynamicFolder + Keeper (Powershell Core) + Get dynamic credentials from Keeper Secrets Manager + + + +

Keeper (Powershell) Dynamic Folder

+ +

Version: 1.0.0
+Author: https://github.com/WillEllis

+ +

How to use

+ +

Ensure you set the RoyalTS script interpreter as Powershell Core. E.g. "C:\Program Files\PowerShell\7\pwsh.exe"

+ +

Create a Keeper application

+ +

You will need to create an application in Keeper and get a one time access token. Follow the quick start guide here: Keeper Create an Application

+ +

Create a Keeper application

+ +

Setup Keeper Secrets Manager for Powershell (in Powershell core) following this guide Keeper Powershell Plugin - Installation

+ +

Connect Dynamic Folder to Powershell Keeper Vault

+ +

If you've done the above then you'll have a Powershell Vault in place for Keeper. Simply set the name of the vault and the password (if set) within the custom properties of this Dynamic folder.

+ +

 

+]]>
+ + + PowerShell Vault Name + Text + TODO + + + PowerShell Vault Password + Protected + TODO + + + powershell + + powershell + + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file From 462bb344d23ee8c2029466119532a7370dd9c9b5 Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 14:56:09 +0100 Subject: [PATCH 08/13] [Refactor] Transform all Keychain scripts --- .../Keychain/Keychain (Python).rdfe | 22 - .../Keychain/Keychain (Python).rdfx | 408 ++++++++++++++++++ 2 files changed, 408 insertions(+), 22 deletions(-) delete mode 100644 Dynamic Folder/Keychain/Keychain (Python).rdfe create mode 100644 Dynamic Folder/Keychain/Keychain (Python).rdfx diff --git a/Dynamic Folder/Keychain/Keychain (Python).rdfe b/Dynamic Folder/Keychain/Keychain (Python).rdfe deleted file mode 100644 index c800c67..0000000 --- a/Dynamic Folder/Keychain/Keychain (Python).rdfe +++ /dev/null @@ -1,22 +0,0 @@ -{ - "Name": "Dynamic Folder Export", - "Objects": [ - { - "Notes": "

Keychain (Python)

\n\n

Version: 1.0
\nAuthor: Royal Apps

\n\n

Description

\n\n

This script dynamically retrieves usernames and passwords from the macOS Keychain. You provide the names of the keychain items as a semicolon separated list in the custom properties section. When reloading the dynamic folder, a dynamic credential object will be created for each provided keychain item. When opening a connection that uses one of the dynamic credentials, the username and password will be requested from the keychain.

\n\n

Configuration

\n\n
    \n\t
  • Add the names of keychain items you want to retrieve as a semicolon separated list to the "Keychain Item Names" custom property.
  • \n
\n\n

Prerequisits

\n\n
    \n\t
  • Python 3 must be installed and configured.
  • \n
\n", - "Script": "import sys\nimport subprocess\nimport json\nimport re\nimport binascii\n\ndef print_to_stderr(text: str, should_exit: bool):\n\tprint(text, file=sys.stderr)\n\n\tif should_exit:\n\t\texit(1)\n\ndef hex_to_string(hex: str) -> str:\n\tunhexified_string = str(binascii.unhexlify(hex), 'utf-8')\n\n\treturn unhexified_string\n\ndef run_subprocess(command: str):\n\treturn subprocess.run(command, shell=True, check=True, capture_output=True)\n\ndef get_keychain_item(item_name: str, include_password: bool) -> tuple[str, str]:\n\tkc_output = None\n\n\ttry:\n\t\tkc_command_generic = f\"security find-generic-password -l '{item_name}'\"\n\n\t\tif include_password:\n\t\t\tkc_command_generic += ' -g'\n\n\t\tkc_output = run_subprocess(kc_command_generic)\n\texcept subprocess.CalledProcessError as e:\n\t\ttry:\n\t\t\tkc_command_internet = f\"security find-internet-password -l '{item_name}'\"\n\n\t\t\tif include_password:\n\t\t\t\tkc_command_internet += ' -g'\n\n\t\t\tkc_output = run_subprocess(kc_command_internet)\n\t\texcept subprocess.CalledProcessError as e:\n\t\t\tkc_error = e.stderr.decode().strip()\n\n\t\t\twrapped_kc_error = f'An error occurred while retrieving an item named \"{item_name}\" from the keychain.\\n\\n{kc_error}'\n\n\t\t\tprint_to_stderr(wrapped_kc_error, True)\n\n\tif kc_output is None:\n\t\tprint_to_stderr(\"No output\", True)\n\t\n\tkc_standard_output = kc_output.stdout.decode()\n\tkc_error_output = ''\n\n\tif kc_output.stderr is not None:\n\t\tkc_error_output = kc_output.stderr.decode()\n\n\treturn (kc_standard_output, kc_error_output)\n\ndef get_keychain_detail(kc_details_output: str, key: str) -> str:\n\tkc_ascii_match = re.search(f'.*?\\\"{key}\\\".*?=\\\"(.*)\\\"', kc_details_output)\n\n\tif kc_ascii_match is not None:\n\t\t# Extract ASCII Value\n\t\tkc_value = kc_ascii_match.group(1)\n\n\t\treturn kc_value\n\t\n\tkc_hex_match = re.search(f'.*?\\\"{key}\\\".*?=0x(.*?)\\s', kc_details_output)\n\n\tif kc_hex_match is not None:\n\t\t# Extract Non-ASCII Value\n\t\tkc_value = hex_to_string(kc_hex_match.group(1))\n\n\t\treturn kc_value\n\t\n\treturn None\n\ndef get_keychain_comment(kc_details_output: str) -> str:\n\tkc_value = get_keychain_detail(kc_details_output, \"icmt\")\n\n\tif kc_value == \"default\":\n\t\tkc_value = None\n\n\treturn kc_value\n\ndef get_keychain_protocol(kc_details_output: str) -> str:\n\tkc_value = get_keychain_detail(kc_details_output, \"ptcl\")\n\n\treturn kc_value\n\ndef get_keychain_server(kc_details_output: str) -> str:\n\tkc_value = get_keychain_detail(kc_details_output, \"srvr\")\n\n\treturn kc_value\n\ndef get_keychain_path(kc_details_output: str) -> str:\n\tkc_value = get_keychain_detail(kc_details_output, \"path\")\n\n\treturn kc_value\n\ndef get_keychain_url(kc_details_output: str) -> str:\n\tkc_protocol = get_keychain_protocol(kc_details_output)\n\tkc_server = get_keychain_server(kc_details_output)\n\tkc_path = get_keychain_path(kc_details_output)\n\n\tkc_url = None\n\n\tif kc_protocol is not None:\n\t\tif kc_protocol == \"htps\":\n\t\t\tkc_url = \"https://\"\n\t\telif kc_protocol == \"http\":\n\t\t\tkc_url = \"http://\"\n\n\tif kc_server is not None:\n\t\tif kc_url is None:\n\t\t\tkc_url = \"\"\n\n\t\tkc_url += kc_server\n\n\tif kc_url is None:\n\t\treturn None\n\n\tif kc_path is not None:\n\t\tkc_url += kc_path\n\n\treturn kc_url\n\ndef get_keychain_account(kc_details_output: str) -> str:\n\tkc_value = get_keychain_detail(kc_details_output, \"acct\")\n\n\tif kc_value == None:\n\t\tprint_to_stderr(\"Username was not found in Keychain output.\", True)\n\t\n\treturn kc_value\n\ndef get_dynamic_credential(name: str, id: str, username: str, description: str, url: str) -> object:\n\tdynamic_credential = {\n\t\t\"Type\": \"DynamicCredential\",\n\t\t\"ID\": id,\n\t\t\"Name\": name\n\t}\n\n\tif username is not None:\n\t\tdynamic_credential[\"Username\"] = username\n\t\n\tif description is not None:\n\t\tdynamic_credential[\"Description\"] = description\n\n\tif url is not None:\n\t\tdynamic_credential[\"URL\"] = url\n\n\treturn dynamic_credential\n\ndef get_dynamic_credentials(names_string: str) -> list[object]:\n\tnames = list(filter(None, names_string.split(';')))\n\tdynamic_credentials = [ ]\n\n\tfor name in names:\n\t\tkc_output = get_keychain_item(name, False)\n\n\t\tif kc_output is None or kc_output[0] is None:\n\t\t\tprint_to_stderr(f'The item \"{name}\" was not found in the Keychain.', True)\n\n\t\tusername = get_keychain_account(kc_output[0])\n\t\tcomment = get_keychain_comment(kc_output[0])\n\n\t\tif comment is not None:\n\t\t\tcomment = comment.replace('\\r\\n', '\\n').replace('\\r', '\\n').replace('\\n', ' ')\n\n\t\turl = get_keychain_url(kc_output[0])\n\t\t\n\t\tdynamic_credential = get_dynamic_credential(name, name, username, comment, url)\n\n\t\tdynamic_credentials.append(dynamic_credential)\n\t\n\treturn dynamic_credentials\n\ndef get_store(objects: list[object]) -> object:\n\treturn {\n\t\t\"Objects\": objects\n\t}\n\nkc_item_names=r'$CustomProperty.KeychainItemNames$'\n\ndynamic_credentials = get_dynamic_credentials(kc_item_names)\nstore = get_store(dynamic_credentials)\nprint(json.dumps(store))", - "DynamicCredentialScript": "import sys\nimport subprocess\nimport json\nimport re\nimport binascii\n\ndef print_to_stderr(text: str, should_exit: bool):\n\tprint(text, file=sys.stderr)\n\n\tif should_exit:\n\t\texit(1)\n\ndef hex_to_string(hex: str) -> str:\n\tunhexified_string = str(binascii.unhexlify(hex), 'utf-8')\n\n\treturn unhexified_string\n\ndef run_subprocess(command: str):\n\treturn subprocess.run(command, shell=True, check=True, capture_output=True)\n\ndef get_keychain_item(item_name: str, include_password: bool) -> tuple[str, str]:\n\tkc_output = None\n\n\ttry:\n\t\tkc_command_generic = f\"security find-generic-password -l '{item_name}'\"\n\n\t\tif include_password:\n\t\t\tkc_command_generic += ' -g'\n\n\t\tkc_output = run_subprocess(kc_command_generic)\n\texcept subprocess.CalledProcessError as e:\n\t\ttry:\n\t\t\tkc_command_internet = f\"security find-internet-password -l '{item_name}'\"\n\n\t\t\tif include_password:\n\t\t\t\tkc_command_internet += ' -g'\n\n\t\t\tkc_output = run_subprocess(kc_command_internet)\n\t\texcept subprocess.CalledProcessError as e:\n\t\t\tkc_error = e.stderr.decode().strip()\n\n\t\t\twrapped_kc_error = f'An error occurred while retrieving an item named \"{item_name}\" from the keychain.\\n\\n{kc_error}'\n\n\t\t\tprint_to_stderr(wrapped_kc_error, True)\n\n\tif kc_output is None:\n\t\tprint_to_stderr(\"No output\", True)\n\t\n\tkc_standard_output = kc_output.stdout.decode()\n\tkc_error_output = ''\n\n\tif kc_output.stderr is not None:\n\t\tkc_error_output = kc_output.stderr.decode()\n\n\treturn (kc_standard_output, kc_error_output)\n\ndef get_keychain_detail(kc_details_output: str, key: str) -> str:\n\tkc_ascii_match = re.search(f'.*?\\\"{key}\\\".*?=\\\"(.*)\\\"', kc_details_output)\n\n\tif kc_ascii_match is not None:\n\t\t# Extract ASCII Value\n\t\tkc_value = kc_ascii_match.group(1)\n\n\t\treturn kc_value\n\t\n\tkc_hex_match = re.search(f'.*?\\\"{key}\\\".*?=0x(.*?)\\s', kc_details_output)\n\n\tif kc_hex_match is not None:\n\t\t# Extract Non-ASCII Value\n\t\tkc_value = hex_to_string(kc_hex_match.group(1))\n\n\t\treturn kc_value\n\t\n\treturn None\n\ndef get_keychain_comment(kc_details_output: str) -> str:\n\tkc_value = get_keychain_detail(kc_details_output, \"icmt\")\n\n\tif kc_value == \"default\":\n\t\tkc_value = None\n\n\treturn kc_value\n\ndef get_keychain_protocol(kc_details_output: str) -> str:\n\tkc_value = get_keychain_detail(kc_details_output, \"ptcl\")\n\n\treturn kc_value\n\ndef get_keychain_server(kc_details_output: str) -> str:\n\tkc_value = get_keychain_detail(kc_details_output, \"srvr\")\n\n\treturn kc_value\n\ndef get_keychain_path(kc_details_output: str) -> str:\n\tkc_value = get_keychain_detail(kc_details_output, \"path\")\n\n\treturn kc_value\n\ndef get_keychain_url(kc_details_output: str) -> str:\n\tkc_protocol = get_keychain_protocol(kc_details_output)\n\tkc_server = get_keychain_server(kc_details_output)\n\tkc_path = get_keychain_path(kc_details_output)\n\n\tkc_url = None\n\n\tif kc_protocol is not None:\n\t\tif kc_protocol == \"htps\":\n\t\t\tkc_url = \"https://\"\n\t\telif kc_protocol == \"http\":\n\t\t\tkc_url = \"http://\"\n\n\tif kc_server is not None:\n\t\tif kc_url is None:\n\t\t\tkc_url = \"\"\n\n\t\tkc_url += kc_server\n\n\tif kc_url is None:\n\t\treturn None\n\n\tif kc_path is not None:\n\t\tkc_url += kc_path\n\n\treturn kc_url\n\ndef get_keychain_account(kc_details_output: str) -> str:\n\tkc_value = get_keychain_detail(kc_details_output, \"acct\")\n\n\tif kc_value == None:\n\t\tprint_to_stderr(\"Username was not found in Keychain output.\", True)\n\t\n\treturn kc_value\n\ndef get_keychain_password(kc_password_output: str) -> str:\n\tkc_password_match = re.search('^password:\\s(.*)', kc_password_output)\n\n\tif kc_password_match is None:\n\t\tprint_to_stderr(\"Password was not found\", True)\n\n\tkc_password_string = kc_password_match.group(1)\n\n\tkc_password_ascii_match = re.search('^\\\"(.*)\\\"$', kc_password_string)\n\n\tkc_password = \"\"\n\n\tif kc_password_ascii_match is not None:\n\t\t# Extract ASCII Password\n\t\tkc_password = kc_password_ascii_match.group(1)\n\telse:\n\t\t# Extract Non-ASCII Password\n\t\tkc_password_unicode_match = re.search('^0x(.*?)\\s+?', kc_password_string)\n\n\t\tif kc_password_unicode_match is None:\n\t\t\tprint_to_stderr(\"Password was not found\", True)\n\t\t\n\t\tkc_password_hex = kc_password_unicode_match.group(1)\n\t\tkc_password = hex_to_string(kc_password_hex)\n\t\n\treturn kc_password\n\ndef get_username_password(kc_item_name: str) -> tuple[str, str]:\n\tkc_output = get_keychain_item(kc_item_name, True)\n\n\tkc_account = get_keychain_account(kc_output[0])\n\tkc_password = get_keychain_password(kc_output[1])\n\n\treturn (kc_account, kc_password)\n\ndef get_dynamic_credential_content(username: str, password: str) -> object:\n\treturn {\n\t\t\"Username\": username,\n\t\t\"Password\": password\n\t}\n\nkc_item_name=r'$DynamicCredential.EffectiveID$'\nkc_username_password = get_username_password(kc_item_name)\ndynamic_credential_content = get_dynamic_credential_content(kc_username_password[0], kc_username_password[1])\n\nprint(json.dumps(dynamic_credential_content))", - "Type": "DynamicFolder", - "Name": "Keychain (Python)", - "Description": "This script dynamically retrieves usernames and passwords from the macOS Keychain.", - "CustomProperties": [ - { - "Name": "Keychain Item Names", - "Type": "Text", - "Value": "TODO" - } - ], - "ScriptInterpreter": "python", - "DynamicCredentialScriptInterpreter": "python" - } - ] -} \ No newline at end of file diff --git a/Dynamic Folder/Keychain/Keychain (Python).rdfx b/Dynamic Folder/Keychain/Keychain (Python).rdfx new file mode 100644 index 0000000..24b1ea3 --- /dev/null +++ b/Dynamic Folder/Keychain/Keychain (Python).rdfx @@ -0,0 +1,408 @@ + + Dynamic Folder Export + + + DynamicFolder + Keychain (Python) + This script dynamically retrieves usernames and passwords from the macOS Keychain. + Keychain (Python) + +

Version: 1.0
+Author: Royal Apps

+ +

Description

+ +

This script dynamically retrieves usernames and passwords from the macOS Keychain. You provide the names of the keychain items as a semicolon separated list in the custom properties section. When reloading the dynamic folder, a dynamic credential object will be created for each provided keychain item. When opening a connection that uses one of the dynamic credentials, the username and password will be requested from the keychain.

+ +

Configuration

+ +
    +
  • Add the names of keychain items you want to retrieve as a semicolon separated list to the "Keychain Item Names" custom property.
  • +
+ +

Prerequisits

+ +
    +
  • Python 3 must be installed and configured.
  • +
+]]>
+ + + Keychain Item Names + Text + TODO + + + python + + python + str: + unhexified_string = str(binascii.unhexlify(hex), 'utf-8') + + return unhexified_string + +def run_subprocess(command: str): + return subprocess.run(command, shell=True, check=True, capture_output=True) + +def get_keychain_item(item_name: str, include_password: bool) -> tuple[str, str]: + kc_output = None + + try: + kc_command_generic = f"security find-generic-password -l '{item_name}'" + + if include_password: + kc_command_generic += ' -g' + + kc_output = run_subprocess(kc_command_generic) + except subprocess.CalledProcessError as e: + try: + kc_command_internet = f"security find-internet-password -l '{item_name}'" + + if include_password: + kc_command_internet += ' -g' + + kc_output = run_subprocess(kc_command_internet) + except subprocess.CalledProcessError as e: + kc_error = e.stderr.decode().strip() + + wrapped_kc_error = f'An error occurred while retrieving an item named "{item_name}" from the keychain.\n\n{kc_error}' + + print_to_stderr(wrapped_kc_error, True) + + if kc_output is None: + print_to_stderr("No output", True) + + kc_standard_output = kc_output.stdout.decode() + kc_error_output = '' + + if kc_output.stderr is not None: + kc_error_output = kc_output.stderr.decode() + + return (kc_standard_output, kc_error_output) + +def get_keychain_detail(kc_details_output: str, key: str) -> str: + kc_ascii_match = re.search(f'.*?\"{key}\".*?=\"(.*)\"', kc_details_output) + + if kc_ascii_match is not None: + # Extract ASCII Value + kc_value = kc_ascii_match.group(1) + + return kc_value + + kc_hex_match = re.search(f'.*?\"{key}\".*?=0x(.*?)\s', kc_details_output) + + if kc_hex_match is not None: + # Extract Non-ASCII Value + kc_value = hex_to_string(kc_hex_match.group(1)) + + return kc_value + + return None + +def get_keychain_comment(kc_details_output: str) -> str: + kc_value = get_keychain_detail(kc_details_output, "icmt") + + if kc_value == "default": + kc_value = None + + return kc_value + +def get_keychain_protocol(kc_details_output: str) -> str: + kc_value = get_keychain_detail(kc_details_output, "ptcl") + + return kc_value + +def get_keychain_server(kc_details_output: str) -> str: + kc_value = get_keychain_detail(kc_details_output, "srvr") + + return kc_value + +def get_keychain_path(kc_details_output: str) -> str: + kc_value = get_keychain_detail(kc_details_output, "path") + + return kc_value + +def get_keychain_url(kc_details_output: str) -> str: + kc_protocol = get_keychain_protocol(kc_details_output) + kc_server = get_keychain_server(kc_details_output) + kc_path = get_keychain_path(kc_details_output) + + kc_url = None + + if kc_protocol is not None: + if kc_protocol == "htps": + kc_url = "https://" + elif kc_protocol == "http": + kc_url = "http://" + + if kc_server is not None: + if kc_url is None: + kc_url = "" + + kc_url += kc_server + + if kc_url is None: + return None + + if kc_path is not None: + kc_url += kc_path + + return kc_url + +def get_keychain_account(kc_details_output: str) -> str: + kc_value = get_keychain_detail(kc_details_output, "acct") + + if kc_value == None: + print_to_stderr("Username was not found in Keychain output.", True) + + return kc_value + +def get_keychain_password(kc_password_output: str) -> str: + kc_password_match = re.search('^password:\s(.*)', kc_password_output) + + if kc_password_match is None: + print_to_stderr("Password was not found", True) + + kc_password_string = kc_password_match.group(1) + + kc_password_ascii_match = re.search('^\"(.*)\"$', kc_password_string) + + kc_password = "" + + if kc_password_ascii_match is not None: + # Extract ASCII Password + kc_password = kc_password_ascii_match.group(1) + else: + # Extract Non-ASCII Password + kc_password_unicode_match = re.search('^0x(.*?)\s+?', kc_password_string) + + if kc_password_unicode_match is None: + print_to_stderr("Password was not found", True) + + kc_password_hex = kc_password_unicode_match.group(1) + kc_password = hex_to_string(kc_password_hex) + + return kc_password + +def get_username_password(kc_item_name: str) -> tuple[str, str]: + kc_output = get_keychain_item(kc_item_name, True) + + kc_account = get_keychain_account(kc_output[0]) + kc_password = get_keychain_password(kc_output[1]) + + return (kc_account, kc_password) + +def get_dynamic_credential_content(username: str, password: str) -> object: + return { + "Username": username, + "Password": password + } + +kc_item_name=r'$DynamicCredential.EffectiveID$' +kc_username_password = get_username_password(kc_item_name) +dynamic_credential_content = get_dynamic_credential_content(kc_username_password[0], kc_username_password[1]) + +print(json.dumps(dynamic_credential_content))]]> + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file From 747b9059b7a309f1db62474a8bbd1dc6f57a1611 Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 15:08:33 +0100 Subject: [PATCH 09/13] [Refactor] Transform all Passwordstate scripts --- .../Passwordstate (PowerShell).rdfe | 27 --- .../Passwordstate (PowerShell).rdfx | 208 ++++++++++++++++++ ...sed on management module (PowerShell).rdfe | 1 - ...sed on management module (PowerShell).rdfx | 101 +++++++++ 4 files changed, 309 insertions(+), 28 deletions(-) delete mode 100644 Dynamic Folder/Passwordstate/Passwordstate (PowerShell).rdfe create mode 100644 Dynamic Folder/Passwordstate/Passwordstate (PowerShell).rdfx delete mode 100644 Dynamic Folder/Passwordstate/Passwordstate - Based on management module (PowerShell).rdfe create mode 100644 Dynamic Folder/Passwordstate/Passwordstate - Based on management module (PowerShell).rdfx diff --git a/Dynamic Folder/Passwordstate/Passwordstate (PowerShell).rdfe b/Dynamic Folder/Passwordstate/Passwordstate (PowerShell).rdfe deleted file mode 100644 index 0a2c08b..0000000 --- a/Dynamic Folder/Passwordstate/Passwordstate (PowerShell).rdfe +++ /dev/null @@ -1,27 +0,0 @@ -{ - "Name": "Dynamic Folder Export", - "Objects": [ - { - "Type": "DynamicFolder", - "Name": "Passwordstate (PowerShell)", - "Description": "This Dynamic Folder sample for Passwordstate supports Dynamic Credentials or regular credentials.", - "Notes": "

Dynamic Folder sample for Passwordstate

\n\n

Version: 1.0.0
\nAuthor: Royal Apps

\n\n

This Dynamic Folder sample for Passwordstate supports Dynamic Credentials and regular credentials.

\n\n

Requirements

\n\n
    \n\t
  • This script has only been tested with PowerShell Core 6.x. If you're using an older version, adjustments might be necessary.
  • \n
\n\n

Setup

\n\n
    \n\t
  • Enter your "Server URL" in the "Custom Properties" section. (ie. https://passwordstatehost:9119)
  • \n\t
  • If you're using an untrusted SSL certificate on your server, set Skip Certificate Check to "Yes".
  • \n\t
  • Assign a credential to the dynamic folder which contains the following information:\n\t
      \n\t\t
    • Username: Either leave the username blank if you're using a system-wide API key and want to retrieve all credentials or enter the ID of the password list you want to retrieve.
    • \n\t\t
    • Password: Enter your Passwordstate API key.
    • \n\t
    \n\t
  • \n\t
  • By default, the dynamic folder script generates dynamic credentials. If you want to use regular credentials instead, edit the last line of the dynamic folder script and change -createDynamicCredential $true to -createDynamicCredential $false.
  • \n
\n", - "CustomProperties": [ - { - "Name": "Server URL", - "Type": "URL", - "Value": "TODO" - }, - { - "Name": "Skip Certificate Check", - "Type": "YesNo", - "Value": "False" - } - ], - "ScriptInterpreter": "powershell", - "DynamicCredentialScriptInterpreter": "powershell", - "DynamicCredentialScript": "$ErrorActionPreference = \"Stop\"\n\nfunction Get-DynamicCredential-Result ($passwordObject) {\n\t$username = $passwordObject.UserName\n\t$password = $passwordObject.Password\n\n\t$result = New-Object pscustomobject -Property @{\n\t\t\"Username\" = $username;\n\t\t\"Password\" = $password;\n\t}\n\t\n\treturn $result\n}\n\nfunction Get-Password($url, $apiKey, $passwordID, $preventAuditing, $skipCertificateCheck) {\n\t$api = \"$url/api\"\n\t\n $headers = @{\n \"APIKey\" = $apiKey\n\t}\n\n\t$passwordsBasePath = \"/passwords/\"\n\n\t$preventAuditingParam = \"PreventAuditing=false\"\n\n\tif ($preventAuditing) {\n\t\t$preventAuditingParam = \"PreventAuditing=true\"\n\t}\n\t\n\t$urlPassword = $api + $passwordsBasePath + $passwordID + \"?\" + $preventAuditingParam\n\t\n\t$webRequestParams = @{}\n\n\tif ($skipCertificateCheck) {\n\t\t$webRequestParams[\"-SkipCertificateCheck\"] = $true\n\t}\n\n\t$passwordObjectJSON = Invoke-WebRequest -Uri $urlPassword -Headers $headers @webRequestParams\n\t$passwordObject = (ConvertFrom-Json $passwordObjectJSON.Content)\n\n\t$credentialResult = Get-DynamicCredential-Result -passwordObject $passwordObject\n\n\t$credentialResultJSON = (ConvertTo-Json -InputObject $credentialResult -Depth 100)\n\n $credentialResultJSON\n}\n\n$baseURL = \"$CustomProperty.ServerURL$\"\n$apiKey = \"$EffectivePassword$\"\n$passwordID = \"$DynamicCredential.EffectiveID$\"\n$skipCertificateCheck = \"$CustomProperty.SkipCertificateCheck$\" -like \"yes\"\n\nGet-Password -url $baseURL -apiKey $apiKey -passwordID $passwordID -preventAuditing $false -skipCertificateCheck $skipCertificateCheck", - "Script": "$ErrorActionPreference = \"Stop\"\n\nfunction Get-Credential ($passwordObject, $createDynamicCredential) {\n $credentialID = $passwordObject.PasswordID\n\t$credentialName = $passwordObject.Title\n\t$username = \"\"\n\t$password = \"\"\n\t$url = $passwordObject.URL\n\t$notes = $passwordObject.Notes\n\n\t$folderPath = \"\"\n\t\n\tif ($passwordObject.TreePath) {\n\t\t$folderPath = $passwordObject.TreePath\n\t}\n\n\tif ($passwordObject.PasswordList) {\n\t\t$folderPath += \"\\\" + $passwordObject.PasswordList\n\t}\n\n\t$folderPath = $folderPath.TrimStart([char]'\\').Trim()\n\n\t$objectType = \"Credential\"\n\n\tif ($createDynamicCredential) {\n\t\t$objectType = \"DynamicCredential\"\n\t} else {\n\t\t$username = $passwordObject.UserName\n\t\t$password = $passwordObject.Password\n\t}\n \n $credential = New-Object pscustomobject -Property @{\n \"Type\" = $objectType;\n \"ID\" = $credentialID;\n \"Name\" = $credentialName;\n\t\t\"Path\" = $folderPath;\n\t\t\"Username\" = $username;\n\t\t\"Password\" = $password;\n\t\t\"URL\" = $url;\n\t\t\"Notes\" = $notes;\n }\n\n return $credential\n}\n\nfunction Get-Entries($url, $apiKey, $passwordListID, $preventAuditing, $createDynamicCredential, $skipCertificateCheck) {\n\t$api = \"$url/api\"\n\t\n $headers = @{\n \"APIKey\" = $apiKey\n\t}\n\n\t$passwordsBasePath = \"/passwords/\"\n\n\t$queryAllParam = \"QueryAll\"\n\n\t$preventAuditingParam = \"PreventAuditing=false\"\n\n\tif ($preventAuditing) {\n\t\t$preventAuditingParam = \"PreventAuditing=true\"\n\t}\n\t\n\tif ($passwordListID -gt -1) {\n\t\t$urlPasswords = $api + $passwordsBasePath + $passwordListID + \"?\" + $queryAllParam + \"&\" + $preventAuditingParam\n\t} else {\n\t\t$urlPasswords = $api + $passwordsBasePath + \"?\" + $queryAllParam + \"&\" + $preventAuditingParam\n\t}\n\t\n\t$webRequestParams = @{}\n\n\tif ($skipCertificateCheck) {\n\t\t$webRequestParams[\"-SkipCertificateCheck\"] = $true\n\t}\n\n\t$passwordObjectsJSON = Invoke-WebRequest -Uri $urlPasswords -Headers $headers @webRequestParams\n\t$passwordObjects = (ConvertFrom-Json $passwordObjectsJSON.Content)\n\t\n\t$storeObjects = @()\n\n\tForEach ($passwordObject in $passwordObjects) {\n\t\t$credential = Get-Credential -passwordObject $passwordObject -createDynamicCredential $createDynamicCredential\n\t\t\n\t\t$storeObjects += $credential\n\t}\n\t\n\t$store = New-Object pscustomobject -Property @{\n \"Objects\" = $storeObjects;\n }\n\n\t$storeJSON = (ConvertTo-Json -InputObject $store -Depth 100)\n\n $storeJSON\n}\n\n$baseURL = \"$CustomProperty.ServerURL$\"\n$apiKey = \"$EffectivePassword$\"\n$passwordListID = \"$EffectiveUsername$\"\n$skipCertificateCheck = \"$CustomProperty.SkipCertificateCheck$\" -like \"yes\"\n\nGet-Entries -url $baseURL -apiKey $apiKey -passwordListID $passwordListID -preventAuditing $false -createDynamicCredential $true -skipCertificateCheck $skipCertificateCheck" - } - ] -} \ No newline at end of file diff --git a/Dynamic Folder/Passwordstate/Passwordstate (PowerShell).rdfx b/Dynamic Folder/Passwordstate/Passwordstate (PowerShell).rdfx new file mode 100644 index 0000000..86d4a77 --- /dev/null +++ b/Dynamic Folder/Passwordstate/Passwordstate (PowerShell).rdfx @@ -0,0 +1,208 @@ + + Dynamic Folder Export + + + DynamicFolder + Passwordstate (PowerShell) + This Dynamic Folder sample for Passwordstate supports Dynamic Credentials or regular credentials. + Dynamic Folder sample for Passwordstate + +

Version: 1.0.0
+Author: Royal Apps

+ +

This Dynamic Folder sample for Passwordstate supports Dynamic Credentials and regular credentials.

+ +

Requirements

+ +
    +
  • This script has only been tested with PowerShell Core 6.x. If you're using an older version, adjustments might be necessary.
  • +
+ +

Setup

+ +
    +
  • Enter your "Server URL" in the "Custom Properties" section. (ie. https://passwordstatehost:9119)
  • +
  • If you're using an untrusted SSL certificate on your server, set Skip Certificate Check to "Yes".
  • +
  • Assign a credential to the dynamic folder which contains the following information: +
      +
    • Username: Either leave the username blank if you're using a system-wide API key and want to retrieve all credentials or enter the ID of the password list you want to retrieve.
    • +
    • Password: Enter your Passwordstate API key.
    • +
    +
  • +
  • By default, the dynamic folder script generates dynamic credentials. If you want to use regular credentials instead, edit the last line of the dynamic folder script and change -createDynamicCredential $true to -createDynamicCredential $false.
  • +
+]]>
+ + + Server URL + URL + TODO + + + Skip Certificate Check + YesNo + False + + + powershell + + powershell + + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file diff --git a/Dynamic Folder/Passwordstate/Passwordstate - Based on management module (PowerShell).rdfe b/Dynamic Folder/Passwordstate/Passwordstate - Based on management module (PowerShell).rdfe deleted file mode 100644 index cbac994..0000000 --- a/Dynamic Folder/Passwordstate/Passwordstate - Based on management module (PowerShell).rdfe +++ /dev/null @@ -1 +0,0 @@ -{"Name":"Dynamic Folder Export","Objects":[{"Type":"DynamicFolder","Name":"PasswordState","Description":"Get dynamic credentials from passwordstate server","Notes":"\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t

\r\n\t\t\tPassword State Dynamic Folder

\r\n\t\t

\r\n\t\t\tHow to use

\r\n\t\t

Install passwordstate-management powershell module PSGalleryLink

\r\n\t\t\tSetup your passwordstate management environment

\r\n\t\t

First you will need to setup the environment for PasswordState. This prevents you having to enter the api key all the time as it's stored in an encrypted format. Or you can use Windows authentication using the currently logged on user.

\r\n\t\t\tFor API Key

\r\n\t\t

    Set-PasswordStateEnvironment  -baseuri "https://passwordstatserver.co.uk" -apikey "dsiwjdi9e0377dw84w45dsw5sw"

\r\n\t\t\tFor Windows Auth With Pass Through Authentication

\r\n\t\t

    Set-PasswordStateEnvironment  -baseuri "https://passwordstateserver.co.uk" -WindowsAuthOnly

\r\n\t\t\tFor Windows Auth With Custom Credentials

\r\n\t\t

    Set-PasswordStateEnvironment  -baseuri "https://passwordstateserver.co.uk" -customcredentials $(Get-Credential)

This will save a file called passwordstate.json under the users profile folder.

For more infor about the module consult powershell help or the github repository

\r\n\r\n","Script":"$ErrorActionPreference = \"Stop\"\r\n$results = Get-PasswordStatePassword -preventauditing\r\n$credentials = @()\r\nforeach ($item in $results) {\r\n if ($item.Notes -like \"-----BEGIN RSA PRIVATE KEY----*\") {\r\n $credentials += [pscustomobject]@{\r\n Type = \"DynamicCredential\"\r\n Name = $item.Title\r\n ID = $item.PasswordID\r\n\t\t\tUsername = \"\"\r\n\t\t\tPassword = \"\"\r\n KeyFileContent = $item.Notes\r\n\t\t\tPath = $item.TreePath\r\n }\r\n \r\n }\r\n else {\r\n $credentials += [pscustomobject]@{\r\n Type = \"DynamicCredential\"\r\n Name = $item.Title\r\n\t\t\tUsername = \"\"\r\n\t\t\tPassword = \"\"\r\n ID = $item.PasswordID\r\n\t\t\tPath = $item.TreePath\r\n }\r\n \r\n }\r\n}\r\n\r\n\r\n$final = [pscustomobject]@{\r\n Objects = $credentials\r\n}\r\n$final | ConvertTo-Json -Depth 100 | Write-Output","ScriptInterpreter":"powershell","DynamicCredentialScriptInterpreter":"powershell","DynamicCredentialScript":"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n$ErrorActionPreference = \"Stop\"\n$results = Get-PasswordStatePassword -PasswordID \"$DynamicCredential.EffectiveID$\"\n$results.Password = $results.GetPassword()\n$results | Select-Object Username,Password | ConvertTo-Json -Depth 100 | Write-Output"}]} diff --git a/Dynamic Folder/Passwordstate/Passwordstate - Based on management module (PowerShell).rdfx b/Dynamic Folder/Passwordstate/Passwordstate - Based on management module (PowerShell).rdfx new file mode 100644 index 0000000..c616f1b --- /dev/null +++ b/Dynamic Folder/Passwordstate/Passwordstate - Based on management module (PowerShell).rdfx @@ -0,0 +1,101 @@ + + Dynamic Folder Export + + + DynamicFolder + Passwordstate - Based on management module (PowerShell) + Get dynamic credentials from passwordstate server + + + +

Password State Dynamic Folder

+ +

How to use

+ +

Install passwordstate-management powershell module PSGalleryLink

+ +

Setup your passwordstate management environment

+ +

First you will need to setup the environment for PasswordState. This prevents you having to enter the api key all the time as it's stored in an encrypted format. Or you can use Windows authentication using the currently logged on user.

+ +

For API Key

+ +

    Set-PasswordStateEnvironment  -baseuri "https://passwordstatserver.co.uk" -apikey "dsiwjdi9e0377dw84w45dsw5sw"

+ +

For Windows Auth With Pass Through Authentication

+ +

    Set-PasswordStateEnvironment  -baseuri "https://passwordstateserver.co.uk" -WindowsAuthOnly

+ +

For Windows Auth With Custom Credentials

+ +

    Set-PasswordStateEnvironment  -baseuri "https://passwordstateserver.co.uk" -customcredentials $(Get-Credential)

+ +

This will save a file called passwordstate.json under the users profile folder.

+ +

For more infor about the module consult powershell help or the github repository

+]]>
+ powershell + + powershell + + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file From d446bf32503ffb719c10bfc0426b0f9b7ea622df Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 15:10:11 +0100 Subject: [PATCH 10/13] [Refactor] Transform all Pleasant scripts --- .../Pleasant Password (Python).rdfe | 32 - .../Pleasant Password (Python).rdfx | 549 ++++++++++++++++++ 2 files changed, 549 insertions(+), 32 deletions(-) delete mode 100644 Dynamic Folder/Pleasant Password Server/Pleasant Password (Python).rdfe create mode 100644 Dynamic Folder/Pleasant Password Server/Pleasant Password (Python).rdfx diff --git a/Dynamic Folder/Pleasant Password Server/Pleasant Password (Python).rdfe b/Dynamic Folder/Pleasant Password Server/Pleasant Password (Python).rdfe deleted file mode 100644 index 5b88fc8..0000000 --- a/Dynamic Folder/Pleasant Password Server/Pleasant Password (Python).rdfe +++ /dev/null @@ -1,32 +0,0 @@ -{ - "Name": "Dynamic Folder Export", - "Objects": [ - { - "Type": "DynamicFolder", - "Name": "Pleasant Password (Python)", - "Description": "This Dynamic Folder sample for Pleasant Password Server supports Dynamic Credentials, Multi-Factor-Authentication (MFA), APIv4 and APIv5.", - "Notes": "\n\n\n

Dynamic Folder sample for Pleasant Password Server

\n\n

Version: 1.2.3
\nAuthors: Royal Apps, Petr Stepan

\n\n

This Dynamic Folder sample for Pleasant Password Server supports Dynamic Credentials, Multi-Factor-Authentication (MFA), APIv4 and APIv5. Python 2 and Python 3 are supported.

\n\n

Requirements

\n\n
    \n\t
  • Python Module: __future__
  • \n\t
  • Python Module: sys
  • \n\t
  • Python Module: functools
  • \n\t
  • Python Module: json
  • \n\t
  • Python Module: requests
  • \n\t
  • Python Module: urllib3
  • \n\t
  • Python Module: tkinter
  • \n
\n\n

Setup

\n\n
    \n\t
  • Enter your "Server URL" in the "Custom Properties" section (without trailing slash).
  • \n\t
  • Enter your "API Version" in the "Custom Properties" section (defaults to APIv5).\n\t
      \n\t\t
    • Supported version: APIv4, APIv5
    • \n\t
    \n\t
  • \n\t
  • Choose whether you want to omit domain name from credentials in the "Custom Properties" section.
  • \n\t
  • Enter or assign your Pleasant Password Server credentials.
  • \n
\n", - "CustomProperties": [ - { - "Name": "Server URL", - "Type": "URL", - "Value": "TODO" - }, - { - "Name": "API Version", - "Type": "Text", - "Value": "5" - }, - { - "Name": "Omit Domain", - "Type": "YesNo", - "Value": "False" - } - ], - "Script": "from __future__ import print_function\nimport sys\nfrom functools import partial\nimport json\nimport requests\nimport urllib3\n\ntry:\n\t# for Python2\n\tfrom Tkinter import * \nexcept ImportError:\n\t# for Python3\n\tfrom tkinter import *\n\nclass TakeInput(object):\n\tdef __init__(self, request_message):\n\t\tself.root = Tk()\n\n\t\ttitle = \"\"\n\n\t\tif request_message:\n\t\t\ttitle = request_message\n\t\t\t\n\t\t\tif title.endswith(\":\"):\n\t\t\t\ttitle = title[:-1]\n\n\t\tself.root.title(title)\n\n\t\t# Do not allow the user to resize the window\n\t\tself.root.resizable(False, False)\n\t\t\n\t\tself.string = \"\"\n\n\t\tself.frame = Frame(self.root)\n\n\t\tself.acceptInput(request_message)\n\t\tself.frame.pack(padx=17, pady=17)\n\n\tdef acceptInput(self, request_message):\n\t\tr = self.frame\n\n\t\ticon = Label(r, text=\"\", image=\"::tk::icons::question\")\n\t\ticon.grid(row=0, column=0, rowspan=2, sticky=\"w\")\n\n\t\tlabel = Label(r, text=request_message)\n\t\tlabel.grid(row=0, column=1, padx=(9, 0), sticky=\"nw\")\n\t\t\n\t\tself.e = Entry(r, text='Name')\n\t\tself.e.grid(row=1, column=1, padx=(13, 0), sticky=\"nw\")\n\t\tself.e.configure(width=30)\n\t\tself.e.focus_set()\n\n\t\tb = Button(r, text=' OK ', command=self.gettext)\n\t\tb.grid(row=2, column=1, sticky=\"ne\", pady=(10, 0))\n\t\t\n\t\tself.root.bind('', self.gettext)\n\n\tdef gettext(self, event=None):\n\t\tself.string = self.e.get()\n\t\tself.root.destroy()\n\n\tdef getString(self):\n\t\treturn self.string\n\t\n\tdef configureWindowGeometry(self):\n\t\t# Get the window size\n\t\twindow_width = self.root.winfo_width()\n\t\twindow_height = self.root.winfo_height()\n\n\t\t# Get the screen size\n\t\tscreen_width = self.root.winfo_screenwidth()\n\t\tscreen_height = self.root.winfo_screenheight()\n\n\t\t# Get the window position from the top dynamically as well as position from left or right as follows\n\t\tposition_top = int((screen_height / 2) - (window_height / 2))\n\t\tposition_right = int((screen_width / 2) - (window_width / 2))\n\n\t\t# Shift up by a couple of pixels to account for the title bar\n\t\tposition_top -= 30\n\n\t\t# This will center the window\n\t\tself.root.geometry(str(window_width) + \"x\" + str(window_height) + \"+\" + str(position_right) + \"+\" + str(position_top))\n\n\tdef waitForInput(self):\n\t\tself.root.lift()\n\n\t\tself.root.attributes('-topmost', True)\n\t\tself.root.after_idle(self.root.attributes, '-topmost', False)\n\n\t\t# Ensure that layout is ready\n\t\tself.root.update_idletasks()\n\n\t\tself.configureWindowGeometry()\n\n\t\tself.root.mainloop()\n\ndef show_prompt(request_message):\n\tmsg_box = TakeInput(request_message)\n\n\t# loop until the user makes a decision and the window is destroyed\n\tmsg_box.waitForInput()\n\n\treturn msg_box.getString()\n\n\ndef convert_notes_to_html(notes):\n\tif notes is None:\n\t\treturn \"\"\n\telse:\n\t\treturn notes.replace(\"\\r\\n\", \"
\").replace(\"\\r\", \"
\").replace(\"\\n\", \"
\")\n\n\ndef create_credential(url, headers, credential):\n\tcredential_id = credential[\"Id\"]\n\tcredential_name = credential[\"Name\"]\n\tcredential_url = credential[\"Url\"]\n\tcredential_username = credential[\"Username\"]\n\tcredential_notes = convert_notes_to_html(credential[\"Notes\"])\n\tcredential_custom_properties = credential[\"CustomUserFields\"]\n\tcredential_color = \"\"\n\n\tcredential_custom_app_fields = credential.get(\"CustomApplicationFields\", None)\n\n\tif credential_custom_app_fields is not None:\n\t\tcredential_color = credential_custom_app_fields.get(\"ForegroundColor\", \"\")\n\n\tcredential_description = \"\"\n\n\tfor tag in credential[\"Tags\"]:\n\t\ttag_name = tag[\"Name\"]\n\t\tcredential_description += tag_name + \", \"\n\n\tif credential_description.endswith(\", \"):\n\t\tcredential_description = credential_description[:len(credential_description) - 2]\n\n\tcredential = {\n\t\t\"Type\": \"DynamicCredential\",\n\t\t\"ID\": credential_id,\n\t\t\"Name\": credential_name,\n\t\t\"Color\": credential_color,\n\t\t\"URL\": credential_url,\n\t\t\"Username\": credential_username,\n\t\t\"Notes\": credential_notes,\n\t\t\"Description\": credential_description,\n\t\t\"CustomProperties\": credential_custom_properties\n\t}\n\n\treturn credential\n\n\ndef create_credential_group(url, headers, credential_group):\n\tfolder_id = credential_group[\"Id\"]\n\tfolder_name = credential_group[\"Name\"]\n\tfolder_notes = convert_notes_to_html(credential_group[\"Notes\"])\n\n\tfolder_objects = []\n\n\tfor sub_credential_group in credential_group[\"Children\"]:\n\t\tfolder_object = create_credential_group(url, headers, sub_credential_group)\n\t\tfolder_objects.append(folder_object)\n\n\tfor credential in credential_group[\"Credentials\"]:\n\t\tcredential_object = create_credential(url, headers, credential)\n\t\tfolder_objects.append(credential_object)\n\n\tfolder = {\n\t\t\"Type\":\t \"Folder\",\n\t\t\"ID\":\t folder_id,\n\t\t\"Name\":\t folder_name,\n\t\t\"Notes\":\tfolder_notes,\n\t\t\"Objects\": folder_objects\n\t}\n\n\t# No need to create the root folder\n\tif credential_group[\"ParentId\"] == \"00000000-0000-0000-0000-000000000000\" and folder_name == \"Root\":\n\t\treturn folder_objects\n\n\treturn folder\n\ndef call_token_endpoint(url, body, otp_headers):\n\tprintError = partial(print, file=sys.stderr) # python2 compatibility\n\ttry:\n\t\ttoken_json = requests.post(url + \"/OAuth2/Token\", data=body, verify=False, headers=otp_headers)\n\t\ttoken_json.raise_for_status()\n\t\treturn token_json\n\texcept requests.exceptions.HTTPError as e:\n\t\tif \"X-Pleasant-OTP\" in token_json.headers and token_json.headers[\"X-Pleasant-OTP\"] == \"required\":\n\t\t\treturn token_json\n\t\t\n\t\tif token_json.status_code == 400:\n\t\t\tprintError(\"HTTP Error 400: Bad Request - could be a redundant domain name, try to omit it. Details: \",e)\n\t\telse:\n\t\t\tprintError(\"HTTP Error: \",e)\n\t\tsys.exit(1)\n\texcept requests.exceptions.ConnectionError:\n\t\tprintError(\"Connection failed.\")\n\t\tsys.exit(1)\n\texcept requests.exceptions.Timeout:\n\t\tprintError(\"Connection timeout.\")\n\t\tsys.exit(1)\n\texcept requests.exceptions.RequestException as e:\n\t\tprintError(\"An unknown connection error occurred. Details: \",e)\n\t\tsys.exit(1)\n\ndef get_api_string(version):\n\tapi_string_list = {\n\t\t\"4\": \"/api/v4/rest/credentialgroup/\",\n\t\t\"5\": \"/api/v5/rest/folders/\"\n\t}\n\tapi_string = api_string_list.get(version, \"/api/v5/rest/folders/\")\n\n\treturn api_string\n\ndef get_entries(url, username, password):\n\tprintError = partial(print, file=sys.stderr) # python2 compatibility\n\turllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\n\n\ttoken_params = {\n\t\t\"grant_type\": \"password\",\n\t\t\"username\": username,\n\t\t\"password\": password\n\t}\n\n\ttoken_json = call_token_endpoint(url, token_params, None)\n\n\tif not token_json.ok:\n\t\tif \"X-Pleasant-OTP\" in token_json.headers and token_json.headers[\"X-Pleasant-OTP\"] == \"required\":\n\t\t\totp_provider = token_json.headers[\"X-Pleasant-OTP-Provider\"]\n\n\t\t\totp_token = show_prompt(\"Enter your OTP for MFA (\" + otp_provider + \"):\")\n\n\t\t\tif not otp_token:\n\t\t\t\tprintError(\"No token for MFA provided\")\n\t\t\t\treturn \"\"\n\n\t\t\totp_headers = {\n\t\t\t\t\"X-Pleasant-OTP-Provider\": otp_provider,\n\t\t\t\t\"X-Pleasant-OTP\": otp_token\n\t\t\t}\n\n\t\t\ttoken_json = call_token_endpoint(url, token_params, otp_headers)\n\t\telse:\n\t\t\tprintError(\"An unknown error occurred (could be redundant domain name, try to omit it).\")\n\t\t\treturn \"\"\n\n\ttoken = json.loads(token_json.content)[\"access_token\"]\n\n\theaders = {\n\t\t\"Accept\": \"application/json\",\n\t\t\"Authorization\": token\n\t}\n\t\n\tapi_string = get_api_string(r\"$CustomProperty.APIVersion$\")\n\t\n\tcredential_groups_json = requests.get(url + api_string, headers=headers, verify=False)\n\tcredential_groups = json.loads(credential_groups_json.content)\n\n\tstore_objects = []\n\n\tif credential_groups is not list:\n\t\tcredential_groups = [credential_groups]\n\n\tfor credentialGroup in credential_groups:\n\t\tfolder = create_credential_group(url, headers, credentialGroup)\n\t\tstore_objects.extend(folder)\n\n\tstore = {\n\t\t\"Objects\": store_objects\n\t}\n\n\tstore_json = json.dumps(store)\n\n\treturn store_json\n\nif r\"$CustomProperty.OmitDomain$\" == \"Yes\":\n\tprint(get_entries(r\"$CustomProperty.ServerURL$\", r\"$EffectiveUsernameWithoutDomain$\", r\"$EffectivePassword$\"))\nelse:\n\tprint(get_entries(r\"$CustomProperty.ServerURL$\", r\"$EffectiveUsername$\", r\"$EffectivePassword$\"))", - "ScriptInterpreter": "python", - "DynamicCredentialScriptInterpreter": "python", - "DynamicCredentialScript": "from __future__ import print_function\nimport sys\nfrom functools import partial\nimport json\nimport requests\nimport urllib3\n\ntry:\n\t# for Python2\n\tfrom Tkinter import * \nexcept ImportError:\n\t# for Python3\n\tfrom tkinter import *\n\nclass TakeInput(object):\n\tdef __init__(self, request_message):\n\t\tself.root = Tk()\n\n\t\ttitle = \"\"\n\n\t\tif request_message:\n\t\t\ttitle = request_message\n\t\t\t\n\t\t\tif title.endswith(\":\"):\n\t\t\t\ttitle = title[:-1]\n\n\t\tself.root.title(title)\n\n\t\t# Do not allow the user to resize the window\n\t\tself.root.resizable(False, False)\n\t\t\n\t\tself.string = \"\"\n\n\t\tself.frame = Frame(self.root)\n\n\t\tself.acceptInput(request_message)\n\t\tself.frame.pack(padx=17, pady=17)\n\n\tdef acceptInput(self, request_message):\n\t\tr = self.frame\n\n\t\ticon = Label(r, text=\"\", image=\"::tk::icons::question\")\n\t\ticon.grid(row=0, column=0, rowspan=2, sticky=\"w\")\n\n\t\tlabel = Label(r, text=request_message)\n\t\tlabel.grid(row=0, column=1, padx=(9, 0), sticky=\"nw\")\n\t\t\n\t\tself.e = Entry(r, text='Name')\n\t\tself.e.grid(row=1, column=1, padx=(13, 0), sticky=\"nw\")\n\t\tself.e.configure(width=30)\n\t\tself.e.focus_set()\n\n\t\tb = Button(r, text=' OK ', command=self.gettext)\n\t\tb.grid(row=2, column=1, sticky=\"ne\", pady=(10, 0))\n\t\t\n\t\tself.root.bind('', self.gettext)\n\n\tdef gettext(self, event=None):\n\t\tself.string = self.e.get()\n\t\tself.root.destroy()\n\n\tdef getString(self):\n\t\treturn self.string\n\t\n\tdef configureWindowGeometry(self):\n\t\t# Get the window size\n\t\twindow_width = self.root.winfo_width()\n\t\twindow_height = self.root.winfo_height()\n\n\t\t# Get the screen size\n\t\tscreen_width = self.root.winfo_screenwidth()\n\t\tscreen_height = self.root.winfo_screenheight()\n\n\t\t# Get the window position from the top dynamically as well as position from left or right as follows\n\t\tposition_top = int((screen_height / 2) - (window_height / 2))\n\t\tposition_right = int((screen_width / 2) - (window_width / 2))\n\n\t\t# Shift up by a couple of pixels to account for the title bar\n\t\tposition_top -= 30\n\n\t\t# This will center the window\n\t\tself.root.geometry(str(window_width) + \"x\" + str(window_height) + \"+\" + str(position_right) + \"+\" + str(position_top))\n\n\tdef waitForInput(self):\n\t\tself.root.lift()\n\n\t\tself.root.attributes('-topmost', True)\n\t\tself.root.after_idle(self.root.attributes, '-topmost', False)\n\n\t\t# Ensure that layout is ready\n\t\tself.root.update_idletasks()\n\n\t\tself.configureWindowGeometry()\n\n\t\tself.root.mainloop()\n\ndef show_prompt(request_message):\n\tmsg_box = TakeInput(request_message)\n\n\t# loop until the user makes a decision and the window is destroyed\n\tmsg_box.waitForInput()\n\n\treturn msg_box.getString()\n\n\ndef call_token_endpoint(url, body, otp_headers):\n\tprintError = partial(print, file=sys.stderr) # python2 compatibility\n\ttry:\n\t\ttoken_json = requests.post(url + \"/OAuth2/Token\", data=body, verify=False, headers=otp_headers)\n\t\ttoken_json.raise_for_status()\n\t\treturn token_json\n\texcept requests.exceptions.HTTPError as e:\n\t\tif \"X-Pleasant-OTP\" in token_json.headers and token_json.headers[\"X-Pleasant-OTP\"] == \"required\":\n\t\t\treturn token_json\n\t\t\n\t\tif token_json.status_code == 400:\n\t\t\tprintError(\"HTTP Error 400: Bad Request - could be a redundant domain name, try to omit it. Details: \",e)\n\t\telse:\n\t\t\tprintError(\"HTTP Error: \",e)\n\t\tsys.exit(1)\n\texcept requests.exceptions.ConnectionError:\n\t\tprintError(\"Connection failed.\")\n\t\tsys.exit(1)\n\texcept requests.exceptions.Timeout:\n\t\tprintError(\"Connection timeout.\")\n\t\tsys.exit(1)\n\texcept requests.exceptions.RequestException as e:\n\t\tprintError(\"An unknown connection error occurred. Details: \",e)\n\t\tsys.exit(1)\n\ndef get_api_string(version):\n\tapi_string_list = {\n\t\t\"4\": \"/api/v4/rest/credential/\",\n\t\t\"5\": \"/api/v5/rest/entries/\"\n\t}\n\tapi_string = api_string_list.get(version, \"/api/v5/rest/entries\")\n\n\treturn api_string\n\ndef get_dynamic_credential(url, username, password, credential_id):\n\tprintError = partial(print, file=sys.stderr) # python2 compatibility\n\turllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\n\n\ttoken_params = {\n\t\t\"grant_type\": \"password\",\n\t\t\"username\": username,\n\t\t\"password\": password\n\t}\n\n\ttoken_json = call_token_endpoint(url, token_params, None)\n\n\tif not token_json.ok:\n\t\tif \"X-Pleasant-OTP\" in token_json.headers and token_json.headers[\"X-Pleasant-OTP\"] == \"required\":\n\t\t\totp_provider = token_json.headers[\"X-Pleasant-OTP-Provider\"]\n\n\t\t\totp_token = show_prompt(\"Enter your OTP for MFA (\" + otp_provider + \"):\")\n\n\t\t\tif not otp_token:\n\t\t\t\tprintError(\"No token for MFA provided\")\n\t\t\t\treturn \"\"\n\n\t\t\totp_headers = {\n\t\t\t\t\"X-Pleasant-OTP-Provider\": otp_provider,\n\t\t\t\t\"X-Pleasant-OTP\": otp_token\n\t\t\t}\n\n\t\t\ttoken_json = call_token_endpoint(url, token_params, otp_headers)\n\t\telse:\n\t\t\tprintError(\"An unknown error occurred (could be redundant domain name, try to omit it).\")\n\t\t\treturn \"\"\n\n\ttoken = json.loads(token_json.content)[\"access_token\"]\n\n\theaders = {\n\t\t\"Accept\": \"application/json\",\n\t\t\"Authorization\": token\n\t}\n\n\tapi_string = get_api_string(r\"$CustomProperty.APIVersion$\")\n\t\n\tcredential_password_json = requests.get(url + api_string + credential_id + \"/password\", headers=headers, verify=False)\n\tcredential_password = json.loads(credential_password_json.content)\n\n\tcredential = {\n\t\t\"Password\": credential_password\n\t}\n\n\tcredential_json = json.dumps(credential)\n\n\treturn credential_json\n\nif r\"$CustomProperty.OmitDomain$\" == \"Yes\":\n\tprint(get_dynamic_credential(r\"$CustomProperty.ServerURL$\", r\"$EffectiveUsernameWithoutDomain$\", r\"$EffectivePassword$\", r\"$DynamicCredential.EffectiveID$\"))\nelse:\n\tprint(get_dynamic_credential(r\"$CustomProperty.ServerURL$\", r\"$EffectiveUsername$\", r\"$EffectivePassword$\", r\"$DynamicCredential.EffectiveID$\"))" - } - ] -} \ No newline at end of file diff --git a/Dynamic Folder/Pleasant Password Server/Pleasant Password (Python).rdfx b/Dynamic Folder/Pleasant Password Server/Pleasant Password (Python).rdfx new file mode 100644 index 0000000..b587dfa --- /dev/null +++ b/Dynamic Folder/Pleasant Password Server/Pleasant Password (Python).rdfx @@ -0,0 +1,549 @@ + + Dynamic Folder Export + + + DynamicFolder + Pleasant Password (Python) + This Dynamic Folder sample for Pleasant Password Server supports Dynamic Credentials, Multi-Factor-Authentication (MFA), APIv4 and APIv5. + + + +

Dynamic Folder sample for Pleasant Password Server

+ +

Version: 1.2.3
+Authors: Royal Apps, Petr Stepan

+ +

This Dynamic Folder sample for Pleasant Password Server supports Dynamic Credentials, Multi-Factor-Authentication (MFA), APIv4 and APIv5. Python 2 and Python 3 are supported.

+ +

Requirements

+ +
    +
  • Python Module: __future__
  • +
  • Python Module: sys
  • +
  • Python Module: functools
  • +
  • Python Module: json
  • +
  • Python Module: requests
  • +
  • Python Module: urllib3
  • +
  • Python Module: tkinter
  • +
+ +

Setup

+ +
    +
  • Enter your "Server URL" in the "Custom Properties" section (without trailing slash).
  • +
  • Enter your "API Version" in the "Custom Properties" section (defaults to APIv5). +
      +
    • Supported version: APIv4, APIv5
    • +
    +
  • +
  • Choose whether you want to omit domain name from credentials in the "Custom Properties" section.
  • +
  • Enter or assign your Pleasant Password Server credentials.
  • +
+]]>
+ + + Server URL + URL + TODO + + + API Version + Text + TODO + + + Omit Domain + YesNo + False + + + python + + python + ', self.gettext) + + def gettext(self, event=None): + self.string = self.e.get() + self.root.destroy() + + def getString(self): + return self.string + + def configureWindowGeometry(self): + # Get the window size + window_width = self.root.winfo_width() + window_height = self.root.winfo_height() + + # Get the screen size + screen_width = self.root.winfo_screenwidth() + screen_height = self.root.winfo_screenheight() + + # Get the window position from the top dynamically as well as position from left or right as follows + position_top = int((screen_height / 2) - (window_height / 2)) + position_right = int((screen_width / 2) - (window_width / 2)) + + # Shift up by a couple of pixels to account for the title bar + position_top -= 30 + + # This will center the window + self.root.geometry(str(window_width) + "x" + str(window_height) + "+" + str(position_right) + "+" + str(position_top)) + + def waitForInput(self): + self.root.lift() + + self.root.attributes('-topmost', True) + self.root.after_idle(self.root.attributes, '-topmost', False) + + # Ensure that layout is ready + self.root.update_idletasks() + + self.configureWindowGeometry() + + self.root.mainloop() + +def show_prompt(request_message): + msg_box = TakeInput(request_message) + + # loop until the user makes a decision and the window is destroyed + msg_box.waitForInput() + + return msg_box.getString() + + +def call_token_endpoint(url, body, otp_headers): + printError = partial(print, file=sys.stderr) # python2 compatibility + try: + token_json = requests.post(url + "/OAuth2/Token", data=body, verify=False, headers=otp_headers) + token_json.raise_for_status() + return token_json + except requests.exceptions.HTTPError as e: + if "X-Pleasant-OTP" in token_json.headers and token_json.headers["X-Pleasant-OTP"] == "required": + return token_json + + if token_json.status_code == 400: + printError("HTTP Error 400: Bad Request - could be a redundant domain name, try to omit it. Details: ",e) + else: + printError("HTTP Error: ",e) + sys.exit(1) + except requests.exceptions.ConnectionError: + printError("Connection failed.") + sys.exit(1) + except requests.exceptions.Timeout: + printError("Connection timeout.") + sys.exit(1) + except requests.exceptions.RequestException as e: + printError("An unknown connection error occurred. Details: ",e) + sys.exit(1) + +def get_api_string(version): + api_string_list = { + "4": "/api/v4/rest/credential/", + "5": "/api/v5/rest/entries/" + } + api_string = api_string_list.get(version, "/api/v5/rest/entries") + + return api_string + +def get_dynamic_credential(url, username, password, credential_id): + printError = partial(print, file=sys.stderr) # python2 compatibility + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + token_params = { + "grant_type": "password", + "username": username, + "password": password + } + + token_json = call_token_endpoint(url, token_params, None) + + if not token_json.ok: + if "X-Pleasant-OTP" in token_json.headers and token_json.headers["X-Pleasant-OTP"] == "required": + otp_provider = token_json.headers["X-Pleasant-OTP-Provider"] + + otp_token = show_prompt("Enter your OTP for MFA (" + otp_provider + "):") + + if not otp_token: + printError("No token for MFA provided") + return "" + + otp_headers = { + "X-Pleasant-OTP-Provider": otp_provider, + "X-Pleasant-OTP": otp_token + } + + token_json = call_token_endpoint(url, token_params, otp_headers) + else: + printError("An unknown error occurred (could be redundant domain name, try to omit it).") + return "" + + token = json.loads(token_json.content)["access_token"] + + headers = { + "Accept": "application/json", + "Authorization": token + } + + api_string = get_api_string(r"$CustomProperty.APIVersion$") + + credential_password_json = requests.get(url + api_string + credential_id + "/password", headers=headers, verify=False) + credential_password = json.loads(credential_password_json.content) + + credential = { + "Password": credential_password + } + + credential_json = json.dumps(credential) + + return credential_json + +if r"$CustomProperty.OmitDomain$" == "Yes": + print(get_dynamic_credential(r"$CustomProperty.ServerURL$", r"$EffectiveUsernameWithoutDomain$", r"$EffectivePassword$", r"$DynamicCredential.EffectiveID$")) +else: + print(get_dynamic_credential(r"$CustomProperty.ServerURL$", r"$EffectiveUsername$", r"$EffectivePassword$", r"$DynamicCredential.EffectiveID$"))]]> + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file From e1d5966ef1f8052df2bad602ee36f18013f3a625 Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 15:12:03 +0100 Subject: [PATCH 11/13] [Refactor] Transform all Portscan scripts --- .../Port Scan/Port Scan (Python).rdfe | 57 ---- .../Port Scan/Port Scan (Python).rdfx | 251 ++++++++++++++++++ 2 files changed, 251 insertions(+), 57 deletions(-) delete mode 100644 Dynamic Folder/Port Scan/Port Scan (Python).rdfe create mode 100644 Dynamic Folder/Port Scan/Port Scan (Python).rdfx diff --git a/Dynamic Folder/Port Scan/Port Scan (Python).rdfe b/Dynamic Folder/Port Scan/Port Scan (Python).rdfe deleted file mode 100644 index 5c27545..0000000 --- a/Dynamic Folder/Port Scan/Port Scan (Python).rdfe +++ /dev/null @@ -1,57 +0,0 @@ -{ - "Name": "Dynamic Folder Export", - "Objects": [ - { - "Type": "DynamicFolder", - "Name": "Port Scan (Python)", - "Description": "This Dynamic Folder sample scans your main network interface's IP subnet for open ports.", - "Notes": "

Port Scan Dynamic Folder sample

\n\n

Version: 1.0
\nAuthor: Royal Applications

\n\n

This Dynamic Folder sample scans your main network interface's IP subnet for open ports. The connection types/ports to scan can be configured in the "Custom Properties" section.

\n\n

Note

\n\n

Port scans can take a very long time depending on your subnet size, the number of ports enabled for scanning and the configured connection timeout. Please be patient and/or adjust the configuration as needed.

\n\n

Requirements

\n\n
    \n\t
  • Python Module: netifaces
  • \n
\n\n

Setup

\n\n
    \n\t
  • Enable or disable the connection types you want to be scanned in the "Custom Properties" section.
  • \n\t
  • Configure a timeout (in seconds) for each scanned port in the "Custom Properties" section.
  • \n
\n", - "CustomProperties": [ - { - "Name": "Connection types to scan for:", - "Type": "Header", - "Value": "" - }, - { - "Name": "SSH", - "Type": "YesNo", - "Value": "True" - }, - { - "Name": "RDP", - "Type": "YesNo", - "Value": "False" - }, - { - "Name": "VNC", - "Type": "YesNo", - "Value": "False" - }, - { - "Name": "HTTP", - "Type": "YesNo", - "Value": "False" - }, - { - "Name": "HTTPS", - "Type": "YesNo", - "Value": "False" - }, - { - "Name": "Options", - "Type": "Header", - "Value": "" - }, - { - "Name": "Timeout", - "Type": "Text", - "Value": "0.25" - } - ], - "ScriptInterpreter": "python", - "DynamicCredentialScriptInterpreter": "json", - "DynamicCredentialScript": "{\n\t\"Username\": \"user\",\n\t\"Password\": \"pass\"\n}", - "Script": "import sys\nimport struct\nimport json\nimport socket\n\nimport netifaces\nfrom netifaces import *\n\n\nENABLE_LOGGING = False\n\nSOCKET_TIMEOUT = $CustomProperty.Timeout$\n\nPORT_MAPPINGS = {\n\t22: {\n\t\t\"Type\": \"TerminalConnection\",\n\t\t\"NamePostfix\": \" - SSH\"\n\t},\n\t80: {\n\t\t\"Type\": \"WebConnection\",\n\t\t\"NamePostfix\": \" - HTTP\"\n\t},\n\t443: {\n\t\t\"Type\": \"WebConnection\",\n\t\t\"NamePostfix\": \" - HTTPS\"\n\t},\n\t3389: {\n\t\t\"Type\": \"RemoteDesktopConnection\",\n\t\t\"NamePostfix\": \" - RDP\"\n\t},\n\t5900: {\n\t\t\"Type\": \"VNCConnection\",\n\t\t\"NamePostfix\": \" - VNC\"\n\t}\n}\n\n\ndef get_prefix(subnet_mask):\n prefix = sum([bin(int(x)).count('1') for x in subnet_mask.split('.')])\n\n return prefix\n\n\ndef get_all_ips_in_subnet(ip, cidr):\n host_bits = 32 - cidr\n i = struct.unpack('>I', socket.inet_aton(ip))[0] # note the endianness\n start = (i >> host_bits) << host_bits # clear the host bits\n end = start | ((1 << host_bits) - 1)\n\n ips = []\n\n # excludes the first and last address in the subnet\n for i in range(start, end):\n ips.append(socket.inet_ntoa(struct.pack('>I', i)))\n\n return ips\n\n\ndef is_port_open(target, port):\n\tsock = socket.socket(AF_INET, socket.SOCK_STREAM)\n\tsock.settimeout(SOCKET_TIMEOUT)\n\n\tresult = sock.connect_ex((target, port))\n\n\tsock.close()\n\n\tif (result == 0):\n\t\treturn True\n\n\treturn False\n\n\ndef create_connection(object_type, name_postfix, host, port):\n\tname = host\n\n\tif name_postfix:\n\t\tname += name_postfix\n\n\tconnection = {\n\t\t\"Type\": object_type,\n\t\t\"Name\": name,\n\t\t\"ComputerName\": host,\n\t\t\"Port\": port,\n\t\t\"Path\": \"/\" + host\n\t}\n\n\treturn connection\n\n\ndef parse_potential_string_bool(potential_bool):\n\tactual_bool = False\n\t\n\tif isinstance(potential_bool, bool):\n\t\tactual_bool = potential_bool\n\telif isinstance(potential_bool, str):\n\t\tpotential_bool = potential_bool.lower()\n\t\tif potential_bool == \"true\" or potential_bool == \"yes\":\n\t\t\tactual_bool = True\n\n\treturn actual_bool\n\n\ndef get_connections(config):\n\tiface_name = netifaces.gateways()[\"default\"][netifaces.AF_INET][1]\n\n\taddresses = [i['addr'] for i in ifaddresses(iface_name).setdefault(AF_INET, [{\"addr\": \"\"}] )]\n\tnetmasks = [i['netmask'] for i in ifaddresses(iface_name).setdefault(AF_INET, [{\"addr\": \"\"}] )]\n\n\tip = addresses[0]\n\tnetmask = netmasks[0]\n\tcidr = get_prefix(netmask)\n\n\tips = get_all_ips_in_subnet(ip, cidr)\n\n\tconnections = [ ]\n\n\tfor target_to_scan in ips:\n\t\tif ENABLE_LOGGING:\n\t\t\tprint(\"Scanning \" + target_to_scan + \"...\")\n\n\t\tfor port_to_scan, props in PORT_MAPPINGS.items():\n\t\t\tif port_to_scan == 22 and not config[\"ssh\"]:\n\t\t\t\tcontinue\n\n\t\t\tif port_to_scan == 3389 and not config[\"rdp\"]:\n\t\t\t\tcontinue\n\n\t\t\tif port_to_scan == 5900 and not config[\"vnc\"]:\n\t\t\t\tcontinue\n\n\t\t\tif port_to_scan == 80 and not config[\"http\"]:\n\t\t\t\tcontinue\n\n\t\t\tif port_to_scan == 443 and not config[\"https\"]:\n\t\t\t\tcontinue\n\n\t\t\tif is_port_open(target_to_scan, port_to_scan):\n\t\t\t\tobject_type = props[\"Type\"]\n\t\t\t\tname_postfix = props[\"NamePostfix\"]\n\n\t\t\t\tconnection = create_connection(object_type, name_postfix, target_to_scan, port_to_scan)\n\n\t\t\t\tif ENABLE_LOGGING:\n\t\t\t\t\tprint(\"Found open port and created connection:\")\n\t\t\t\t\tprint(connection)\n\n\t\t\t\tconnections.append(connection)\n\n\tstore = {\n\t\t\"Objects\": connections\n\t}\n\n\tstore_json = json.dumps(store)\n\n\treturn store_json\n\nconfig = {\n\t\"ssh\": parse_potential_string_bool(\"$CustomProperty.SSH$\"),\n\t\"rdp\": parse_potential_string_bool(\"$CustomProperty.RDP$\"),\n\t\"vnc\": parse_potential_string_bool(\"$CustomProperty.VNC$\"),\n\t\"http\": parse_potential_string_bool(\"$CustomProperty.HTTP$\"),\n\t\"https\": parse_potential_string_bool(\"$CustomProperty.HTTPS$\")\n}\n\nprint(get_connections(config))" - } - ] -} diff --git a/Dynamic Folder/Port Scan/Port Scan (Python).rdfx b/Dynamic Folder/Port Scan/Port Scan (Python).rdfx new file mode 100644 index 0000000..94ea207 --- /dev/null +++ b/Dynamic Folder/Port Scan/Port Scan (Python).rdfx @@ -0,0 +1,251 @@ + + Dynamic Folder Export + + + DynamicFolder + Port Scan (Python) + This Dynamic Folder sample scans your main network interface's IP subnet for open ports. + Port Scan Dynamic Folder sample + +

Version: 1.0
+Author: Royal Applications

+ +

This Dynamic Folder sample scans your main network interface's IP subnet for open ports. The connection types/ports to scan can be configured in the "Custom Properties" section.

+ +

Note

+ +

Port scans can take a very long time depending on your subnet size, the number of ports enabled for scanning and the configured connection timeout. Please be patient and/or adjust the configuration as needed.

+ +

Requirements

+ +
    +
  • Python Module: netifaces
  • +
+ +

Setup

+ +
    +
  • Enable or disable the connection types you want to be scanned in the "Custom Properties" section.
  • +
  • Configure a timeout (in seconds) for each scanned port in the "Custom Properties" section.
  • +
+]]>
+ + + Connection types to scan for: + Header + + + + SSH + YesNo + True + + + RDP + YesNo + False + + + VNC + YesNo + False + + + HTTP + YesNo + False + + + HTTPS + YesNo + False + + + Options + Header + + + + Timeout + Text + TODO + + + python + + json + + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file From d60d011ae67eb63a5af9536c808dac12b6cbc275 Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 15:13:11 +0100 Subject: [PATCH 12/13] [Refactor] Transform all Thycotic Secret Server scripts --- .../Thycotic Secret Server (PowerShell).rdfe | 22 -- .../Thycotic Secret Server (PowerShell).rdfx | 294 ++++++++++++++++++ 2 files changed, 294 insertions(+), 22 deletions(-) delete mode 100644 Dynamic Folder/Thycotic Secret Server/Thycotic Secret Server (PowerShell).rdfe create mode 100644 Dynamic Folder/Thycotic Secret Server/Thycotic Secret Server (PowerShell).rdfx diff --git a/Dynamic Folder/Thycotic Secret Server/Thycotic Secret Server (PowerShell).rdfe b/Dynamic Folder/Thycotic Secret Server/Thycotic Secret Server (PowerShell).rdfe deleted file mode 100644 index aed80d2..0000000 --- a/Dynamic Folder/Thycotic Secret Server/Thycotic Secret Server (PowerShell).rdfe +++ /dev/null @@ -1,22 +0,0 @@ -{ - "Name": "Dynamic Folder Export", - "Objects": [ - { - "Type": "DynamicFolder", - "Name": "Thycotic Secret Server (PowerShell)", - "Description": "This Dynamic Folder sample for Thycotic Secret Server supports Dynamic Credentials and Multi-Factor-Authentication (MFA).", - "Notes": "

Dynamic Folder sample for Secret Server

\n\n

Version: 1.0.2
\nAuthor: Royal Applications

\n\n

This Dynamic Folder sample for Thycotic Secret Server supports Dynamic Credentials and Multi-Factor-Authentication (MFA).

\n\n

Requirements

\n\n
    \n\t
  • PowerShell 6.0 or higher
  • \n
\n\n

Setup

\n\n
    \n\t
  • Enter your "Server URL" in the "Custom Properties" section.
  • \n\t
  • Enter or assign your Secret Server credentials.
  • \n\t
  • If MFA is required by your server/user, enable it by setting "-requiresMFA" to "$true" instead of "$false" in the last line of both scripts.
  • \n
\n", - "CustomProperties": [ - { - "Name": "Server URL", - "Type": "URL", - "Value": "TODO" - } - ], - "ScriptInterpreter": "powershell", - "DynamicCredentialScriptInterpreter": "powershell", - "DynamicCredentialScript": "$ErrorActionPreference = \"Stop\"\n$ProgressPreference=\"SilentlyContinue\"\n\nfunction Is-MacOS() {\n [String]$os = $PSVersionTable.OS\n\n return $os.StartsWith(\"darwin\", [System.StringComparison]::CurrentCultureIgnoreCase)\n}\n\nfunction Run-Native([String] $command, [Array] $commandArgs) {\n $env:commandlineargumentstring=($commandArgs | %{'\"'+ ($_ -replace '(\\\\*)\"','$1$1\\\"' -replace '(\\\\*)$','$1$1') + '\"'}) -join ' ';\n return & $command --% %commandlineargumentstring%\n}\n\nfunction Show-Prompt-Mac([String] $prompt, [String] $defaultValue) {\n $command = \"/usr/bin/osascript\"\n $script = \"set resp to text returned of (display dialog \"\"$prompt\"\" default answer \"\"$defaultValue\"\" buttons {\"\"Cancel\"\", \"\"OK\"\"} default button \"\"OK\"\")\"\n $commandArgs = @( \"-e\", $script )\n\n $ret = Run-Native -command $command -commandArgs @( \"-e\", $script )\n\n return $ret\n}\n\nfunction Show-Prompt-Windows([String] $prompt, [String] $defaultValue) {\n [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null\n $ret = [Microsoft.VisualBasic.Interaction]::InputBox($prompt, \"\", $defaultValue)\n\n return $ret\n}\n\nfunction Show-Prompt([String] $prompt, [String] $defaultValue) {\n if (Is-MacOS) {\n return Show-Prompt-Mac -prompt $prompt -defaultValue $defaultValue\n } else {\n return Show-Prompt-Windows -prompt $prompt -defaultValue $defaultValue\n }\n}\n\nfunction Convert-Notes-To-HTML ($notes) {\n $notes -Replace \"\\r\\n\", \"
\" -Replace \"\\r\", \"
\" -Replace \"\\n\", \"
\"\n}\n\n$SLUGS_USERNAME = ( \"username\", \"licensed-to\" );\n$SLUGS_DOMAIN = ( \"domain\" );\n$SLUGS_PASSWORD = ( \"password\", \"pin-code\", \"combination\", \"license-key\", \"pin\" );\n$SLUGS_PASSPHRASE = ( \"private-key-passphrase\", \"passphrase\" );\n\nfunction Create-Credential ($restricted) {\n $restrictedItems = $restricted.items\n\n $credentialUsername = \"\"\n $credentialPassword = \"\"\n $credentialPassphrase = \"\"\n \n ForEach ($restrictedItem in $restrictedItems) {\n $restrictedItemValue = $restrictedItem.itemValue\n\n if (!$restrictedItemValue) {\n continue\n }\n\n $slug = $restrictedItem.slug\n \n if ($SLUGS_USERNAME.Contains($slug)) {\n $credentialUsername = $restrictedItemValue\n } elseif ($SLUGS_DOMAIN.Contains($slug)) {\n $credentialDomain = $restrictedItemValue\n } elseif ($SLUGS_PASSWORD.Contains($slug)) {\n $credentialPassword = $restrictedItemValue\n } elseif ($SLUGS_PASSPHRASE.Contains($slug)) {\n $credentialPassphrase = $restrictedItemValue\n }\n }\n\n if ($credentialDomain -and $credentialUsername) {\n $credentialUsername = \"$credentialDomain\\$credentialUsername\"\n }\n \n $credential = New-Object pscustomobject -Property @{\n \"Username\" = $credentialUsername;\n \"Password\" = $credentialPassword;\n \"KeyFilePassphrase\" = $credentialPassphrase;\n }\n\n return $credential\n}\n\nfunction Get-Credential($url, $username, $password, $requiresMFA, $secretID) {\n $api = \"$url/api/v1\"\n $tokenRoute = \"$url/oauth2/token\";\n\n $tokenParams = @{\n grant_type = \"password\";\n username = $username;\n password = $password;\n }\n\n $headers = $null\n\n If ($requiresMFA) {\n $headers = @{\n \"OTP\" = Show-Prompt -prompt \"Enter your OTP for MFA:\"\n }\n }\n\n $tokenJSON = Invoke-WebRequest -SkipCertificateCheck -Uri $tokenRoute -Method POST -Body $tokenParams -Headers $headers\n $token = (ConvertFrom-Json $tokenJSON.Content).access_token\n\n $headers = @{\n \"Authorization\" = \"Bearer $token\"\n }\n\n $restrictedJSON = Invoke-WebRequest -SkipCertificateCheck -Uri \"$api/secrets/$secretID/restricted\" -Headers $headers -Method POST\n $restricted = (ConvertFrom-Json $restrictedJSON.Content)\n\n $credential = Create-Credential -restricted $restricted\n\n $credentialJSON = (ConvertTo-Json -InputObject $credential -Depth 100)\n \n $credentialJSON\n}\n\nGet-Credential -url \"$CustomProperty.ServerURL$\" -username \"$EffectiveUsername$\" -password \"$EffectivePassword$\" -secretID \"$DynamicCredential.EffectiveID$\" -requiresMFA $false", - "Script": "$ErrorActionPreference = \"Stop\"\n$ProgressPreference=\"SilentlyContinue\"\n\nfunction Is-MacOS() {\n [String]$os = $PSVersionTable.OS\n\n return $os.StartsWith(\"darwin\", [System.StringComparison]::CurrentCultureIgnoreCase)\n}\n\nfunction Run-Native([String] $command, [Array] $commandArgs) {\n $env:commandlineargumentstring=($commandArgs | %{'\"'+ ($_ -replace '(\\\\*)\"','$1$1\\\"' -replace '(\\\\*)$','$1$1') + '\"'}) -join ' ';\n return & $command --% %commandlineargumentstring%\n}\n\nfunction Show-Prompt-Mac([String] $prompt, [String] $defaultValue) {\n $command = \"/usr/bin/osascript\"\n $script = \"set resp to text returned of (display dialog \"\"$prompt\"\" default answer \"\"$defaultValue\"\" buttons {\"\"Cancel\"\", \"\"OK\"\"} default button \"\"OK\"\")\"\n $commandArgs = @( \"-e\", $script )\n\n $ret = Run-Native -command $command -commandArgs @( \"-e\", $script )\n\n return $ret\n}\n\nfunction Show-Prompt-Windows([String] $prompt, [String] $defaultValue) {\n [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null\n $ret = [Microsoft.VisualBasic.Interaction]::InputBox($prompt, \"\", $defaultValue)\n\n return $ret\n}\n\nfunction Show-Prompt([String] $prompt, [String] $defaultValue) {\n if (Is-MacOS) {\n return Show-Prompt-Mac -prompt $prompt -defaultValue $defaultValue\n } else {\n return Show-Prompt-Windows -prompt $prompt -defaultValue $defaultValue\n }\n}\n\nfunction Convert-Notes-To-HTML ($notes) {\n $notes -Replace \"\\r\\n\", \"
\" -Replace \"\\r\", \"
\" -Replace \"\\n\", \"
\"\n}\n\nfunction Create-Credential ($apiURL, $secret, $folderDict) {\n $credentialID = $secret.id\n $credentialName = $secret.name\n\n $folderPath = \"\"\n \n if ($secret.folderId -and $folderDict.ContainsKey($secret.folderId)) {\n $folderPath = $folderDict[$secret.folderId]\n }\n \n $credential = New-Object pscustomobject -Property @{\n \"Type\" = \"DynamicCredential\";\n \"ID\" = $credentialID;\n \"Name\" = $credentialName;\n \"Path\" = $folderPath;\n }\n\n return $credential\n}\n\nfunction Get-Entries($url, $username, $password, $requiresMFA) {\n $api = \"$url/api/v1\"\n $tokenRoute = \"$url/oauth2/token\";\n\n $tokenParams = @{\n grant_type = \"password\";\n username = $username;\n password = $password;\n }\n\n $headers = $null\n\n If ($requiresMFA) {\n $headers = @{\n \"OTP\" = Show-Prompt -prompt \"Enter your OTP for MFA:\"\n }\n }\n\n $tokenJSON = Invoke-WebRequest -SkipCertificateCheck -Uri $tokenRoute -Method POST -Body $tokenParams -Headers $headers\n $token = (ConvertFrom-Json $tokenJSON.Content).access_token\n\n $headers = @{\n \"Authorization\" = \"Bearer $token\"\n }\n\n $foldersRequestBody = @{\n \"paging.take\" = 1000;\n }\n\n $foldersJSON = Invoke-WebRequest -SkipCertificateCheck -Uri \"$api/folders\" -Headers $headers -Body $foldersRequestBody\n $folders = (ConvertFrom-Json $foldersJSON.Content)\n\n $folderDict = @{}\n\n ForEach ($folder in $folders.records) {\n $folderDict.Add($folder.id, $folder.folderPath)\n }\n\n $secretsRequestBody = @{\n \"paging.take\" = 1000;\n }\n\n $secretsJSON = Invoke-WebRequest -SkipCertificateCheck -Uri \"$api/secrets\" -Headers $headers -Body $secretsRequestBody\n $secrets = (ConvertFrom-Json $secretsJSON.Content)\n\n $storeObjects = @()\n\n ForEach ($secret in $secrets.records) {\n $credential = Create-Credential -apiURL $api -secret $secret -folderDict $folderDict\n \n $storeObjects += $credential\n }\n\n $store = New-Object pscustomobject -Property @{\n \"Objects\" = $storeObjects;\n }\n\n $storeJSON = (ConvertTo-Json -InputObject $store -Depth 100)\n \n $storeJSON\n}\n\nGet-Entries -url \"$CustomProperty.ServerURL$\" -username \"$EffectiveUsername$\" -password \"$EffectivePassword$\" -requiresMFA $false" - } - ] -} \ No newline at end of file diff --git a/Dynamic Folder/Thycotic Secret Server/Thycotic Secret Server (PowerShell).rdfx b/Dynamic Folder/Thycotic Secret Server/Thycotic Secret Server (PowerShell).rdfx new file mode 100644 index 0000000..138ec3a --- /dev/null +++ b/Dynamic Folder/Thycotic Secret Server/Thycotic Secret Server (PowerShell).rdfx @@ -0,0 +1,294 @@ + + Dynamic Folder Export + + + DynamicFolder + Thycotic Secret Server (PowerShell) + This Dynamic Folder sample for Thycotic Secret Server supports Dynamic Credentials and Multi-Factor-Authentication (MFA). + Dynamic Folder sample for Secret Server + +

Version: 1.0.2
+Author: Royal Applications

+ +

This Dynamic Folder sample for Thycotic Secret Server supports Dynamic Credentials and Multi-Factor-Authentication (MFA).

+ +

Requirements

+ +
    +
  • PowerShell 6.0 or higher
  • +
+ +

Setup

+ +
    +
  • Enter your "Server URL" in the "Custom Properties" section.
  • +
  • Enter or assign your Secret Server credentials.
  • +
  • If MFA is required by your server/user, enable it by setting "-requiresMFA" to "$true" instead of "$false" in the last line of both scripts.
  • +
+]]>
+ + + Server URL + URL + TODO + + + powershell + + powershell + " -Replace "\r", "
" -Replace "\n", "
" +} + +$SLUGS_USERNAME = ( "username", "licensed-to" ); +$SLUGS_DOMAIN = ( "domain" ); +$SLUGS_PASSWORD = ( "password", "pin-code", "combination", "license-key", "pin" ); +$SLUGS_PASSPHRASE = ( "private-key-passphrase", "passphrase" ); + +function Create-Credential ($restricted) { + $restrictedItems = $restricted.items + + $credentialUsername = "" + $credentialPassword = "" + $credentialPassphrase = "" + + ForEach ($restrictedItem in $restrictedItems) { + $restrictedItemValue = $restrictedItem.itemValue + + if (!$restrictedItemValue) { + continue + } + + $slug = $restrictedItem.slug + + if ($SLUGS_USERNAME.Contains($slug)) { + $credentialUsername = $restrictedItemValue + } elseif ($SLUGS_DOMAIN.Contains($slug)) { + $credentialDomain = $restrictedItemValue + } elseif ($SLUGS_PASSWORD.Contains($slug)) { + $credentialPassword = $restrictedItemValue + } elseif ($SLUGS_PASSPHRASE.Contains($slug)) { + $credentialPassphrase = $restrictedItemValue + } + } + + if ($credentialDomain -and $credentialUsername) { + $credentialUsername = "$credentialDomain\$credentialUsername" + } + + $credential = New-Object pscustomobject -Property @{ + "Username" = $credentialUsername; + "Password" = $credentialPassword; + "KeyFilePassphrase" = $credentialPassphrase; + } + + return $credential +} + +function Get-Credential($url, $username, $password, $requiresMFA, $secretID) { + $api = "$url/api/v1" + $tokenRoute = "$url/oauth2/token"; + + $tokenParams = @{ + grant_type = "password"; + username = $username; + password = $password; + } + + $headers = $null + + If ($requiresMFA) { + $headers = @{ + "OTP" = Show-Prompt -prompt "Enter your OTP for MFA:" + } + } + + $tokenJSON = Invoke-WebRequest -SkipCertificateCheck -Uri $tokenRoute -Method POST -Body $tokenParams -Headers $headers + $token = (ConvertFrom-Json $tokenJSON.Content).access_token + + $headers = @{ + "Authorization" = "Bearer $token" + } + + $restrictedJSON = Invoke-WebRequest -SkipCertificateCheck -Uri "$api/secrets/$secretID/restricted" -Headers $headers -Method POST + $restricted = (ConvertFrom-Json $restrictedJSON.Content) + + $credential = Create-Credential -restricted $restricted + + $credentialJSON = (ConvertTo-Json -InputObject $credential -Depth 100) + + $credentialJSON +} + +Get-Credential -url "$CustomProperty.ServerURL$" -username "$EffectiveUsername$" -password "$EffectivePassword$" -secretID "$DynamicCredential.EffectiveID$" -requiresMFA $false]]>
+ ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file From d2e28fc696af91655e309b5dd7b4091779e58937 Mon Sep 17 00:00:00 2001 From: eiabea Date: Mon, 23 Dec 2024 15:14:23 +0100 Subject: [PATCH 13/13] [Refactor] Transform all VMware scripts --- .../VMware/VMware-Pull (PowerShell).rdfe | 32 ---- .../VMware/VMware-Pull (PowerShell).rdfx | 163 ++++++++++++++++++ 2 files changed, 163 insertions(+), 32 deletions(-) delete mode 100644 Dynamic Folder/VMware/VMware-Pull (PowerShell).rdfe create mode 100644 Dynamic Folder/VMware/VMware-Pull (PowerShell).rdfx diff --git a/Dynamic Folder/VMware/VMware-Pull (PowerShell).rdfe b/Dynamic Folder/VMware/VMware-Pull (PowerShell).rdfe deleted file mode 100644 index e209f22..0000000 --- a/Dynamic Folder/VMware/VMware-Pull (PowerShell).rdfe +++ /dev/null @@ -1,32 +0,0 @@ -{ - "Name": "Dynamic Folder Export", - "Objects": [ - { - "Notes": "\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t

VMware ESXi Host / vCenter Dynamic Folder Example

 

This Dynamic Folder pulls all of the VMware VMs from your VMware ESXi Hosts or VMware vCenter environment and puts them into the appropriate DataCenter/Cluster folder.

 

Requirements:

PowerShell 5.1 or higher on Windows

PowerShell 7.2.1 or higher on MacOS (Thanks @lemonmojo)


VMware.PowerCLI Module 12.4.0 or higher

 

Configure the Server URL Custom Property with a comma separated list of ESXi Hosts or vCenter servers.

 

Configure your credentials under the Credentials Tab or leave them blank.

 

\r\n\r\n", - "Script": "$objCred=new-object System.Management.automation.pscredential -ArgumentList '$EffectiveUsername$',(Convertto-securestring '$EffectivePassword$' -AsPlainText -Force)\r\n\r\n$vcServers = '$CustomProperty.ServerURL$'\r\n\r\n$vcServers=$vcServers.split(',')\r\n\r\n\r\nforeach ($vcenter in $vcServers) {\r\n connect-viserver -credential $objCred $vcenter > $null\r\n}\r\n\r\n#write-host 'Loading Virtual Machines...'\r\n$vmList=get-vm | where { $_.PowerState -eq 'PoweredOn' }\r\n\r\n$mySystems=$vmList | select Name,Guest,GuestId,@{n='IPAddress'; e={(get-vmguest -vm $_).Nics.IPAddress }},@{n='Datacenter'; e={($_ | get-datacenter).name } }, @{n='Cluster'; e= {($_ | get-cluster).name} }\r\n$ServerList = new-object System.Collections.ArrayList\r\n\r\n$ipv4Match='^(?:(?:0?0?\\d|0?[1-9]\\d|1\\d\\d|2[0-5][0-5]|2[0-4]\\d)\\.){3}(?:0?0?\\d|0?[1-9]\\d|1\\d\\d|2[0-5][0-5]|2[0-4]\\d)$'\r\n\r\n\r\nforeach ($vm in $mySystems) {\r\n $vmName=$vm.Name\r\n $folderName=\"$($vm.datacenter)/$($vm.cluster)\"\r\n if ($vm.guest.extensiondata.guestfamily -match 'windows') { $vmType='RemoteDesktopConnection'}\r\n if ($vm.guest.extensiondata.guestfamily -match 'Linux') {$vmType='SSH'}\r\n \r\n if ([string]::IsNullOrEmpty($vmType) -eq $true) {\r\n if ($vm.guestid -match 'windows') { \r\n $vmType='RemoteDesktopConnection'\r\n } else {\r\n $vmType='SSH'\r\n }\r\n }\r\n\r\n $IPAddress=($vm.guest.extensiondata.net.ipaddress -match $ipv4Match)[0]\r\n \r\n\tif ($IPAddress -eq $true) {\r\n $IPAddress=$vm.guest.extensiondata.net.ipaddress\r\n }\r\n\r\n if ($vm.guest.extensiondata.guestfamily -match 'windows') {\r\n $tmpObj=[pscustomobject]@{\r\n Name = $vmName\r\n Path = $folderName\r\n ComputerName = $IPAddress\r\n Type = $vmType\r\n\t\tCredentialName = '$CustomProperty.WindowsCredential$'\r\n }\r\n \r\n }\r\n\r\n if ($vm.guest.extensiondata.guestfamily -match 'Linux') {\r\n $tmpObj=[pscustomobject]@{\r\n Name = $vmName\r\n Path = $folderName\r\n ComputerName = $IPAddress\r\n TerminalconnectionType = $vmType\r\n Type='TerminalConnection'\r\n\t\t\tCredentialName = '$CustomProperty.LinuxCredential$'\r\n } \r\n }\r\n\r\n [void] $serverList.add($tmpObj)\r\n\r\n}\r\n\r\n$objRoyalTS=@{}\r\n[void] $objRoyalTS.add('Objects',$serverList)\r\n\r\n#$objRoyalTS | ConvertTo-Json | out-file 'royalts.json'\r\n\r\n\r\n$objRoyalTS | ConvertTo-Json", - "DynamicCredentialScript": "{\n\t\"Objects\": [\n\t\t{\n\t\t\t\"Type\": \"Credential\",\n\t\t\t\"Name\": \"Root\",\n\t\t\t\"Username\": \"root\",\n\t\t\t\"Password\": \"!ehrfew9fe9gew7rgew@\",\n\t\t\t\"ID\": \"000001\",\n\t\t\t\"Path\": \"/Credentials\"\n\t\t}, {\n\t\t\t\"Type\": \"Folder\",\n\t\t\t\"Name\": \"Connections\",\n\t\t\t\"Objects\": [\n\t\t\t\t{\n\t\t\t\t\t\"Type\": \"TerminalConnection\",\n\t\t\t\t\t\"TerminalConnectionType\": \"SSH\",\n\t\t\t\t\t\"Name\": \"VM01\",\n\t\t\t\t\t\"ComputerName\": \"vm01\",\n\t\t\t\t\t\"CredentialID\": \"000001\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t]\n}", - "Type": "DynamicFolder", - "Name": "VMware Virtual Machines", - "Description": "Imports Virtual Machines from VMware ESXi Hosts or vCenter Servers", - "CustomProperties": [ - { - "Name": "Server URL", - "Type": "Text", - "Value": "TODO" - }, - { - "Name": "WindowsCredential", - "Type": "Text", - "Value": "" - }, - { - "Name": "LinuxCredential", - "Type": "Text", - "Value": "" - } - ], - "ScriptInterpreter": "powershell", - "DynamicCredentialScriptInterpreter": "json" - } - ] -} \ No newline at end of file diff --git a/Dynamic Folder/VMware/VMware-Pull (PowerShell).rdfx b/Dynamic Folder/VMware/VMware-Pull (PowerShell).rdfx new file mode 100644 index 0000000..79e9639 --- /dev/null +++ b/Dynamic Folder/VMware/VMware-Pull (PowerShell).rdfx @@ -0,0 +1,163 @@ + + Dynamic Folder Export + + + DynamicFolder + VMware-Pull (PowerShell) + Imports Virtual Machines from VMware ESXi Hosts or vCenter Servers + + + +

VMware ESXi Host / vCenter Dynamic Folder Example

+ +

 

+ +

This Dynamic Folder pulls all of the VMware VMs from your VMware ESXi Hosts or VMware vCenter environment and puts them into the appropriate DataCenter/Cluster folder.

+ +

 

+ +

Requirements:

+ +

PowerShell 5.1 or higher on Windows

+ +

PowerShell 7.2.1 or higher on MacOS (Thanks @lemonmojo)

+ +


+VMware.PowerCLI Module 12.4.0 or higher

+ +

 

+ +

Configure the Server URL Custom Property with a comma separated list of ESXi Hosts or vCenter servers.

+ +

 

+ +

Configure your credentials under the Credentials Tab or leave them blank.

+ +

 

+]]>
+ + + Server URL + Text + TODO + + + WindowsCredential + Text + TODO + + + LinuxCredential + Text + TODO + + + powershell + + json + + ReplaceInline + DynFolder_ + ReplaceInline + DynCredential_ +
+
+
\ No newline at end of file