if True: # open hosts file, get backups and copy to backup server # hosts.csv containing device type, hostname, ip, username and password with open('hosts.csv') as csvfile: read_csv = csv.reader(csvfile, delimiter=',') for row in read_csv: if row[0] == 'F5' and row[7] == 'Yes': backup_file = open(f'F5-Backup_{row[1]}_{date_format}.txt', 'w+') backup = Connect(row[1], row[2], row[3], row[4]) backup = backup.decode('utf-8') for l in backup: backup_file.write(l) ucs_filename = SCP(row[1], row[2], row[3], row[4]) ucs_filename = str(ucs_filename) backup_server_client.copy( f"F5-Backup_{row[1]}_{date_format}.txt", f"{backup_drive}\\F5-Backup_{row[1]}_{date_format}.txt") backup_server_client.copy( f"{ucs_filename}", f"{backup_drive}\\UCS\\{ucs_filename}") backup_file.close() remove_file1 = subprocess.Popen( f'rm F5-Backup_{row[1]}_{date_format}.txt', stdout=subprocess.PIPE, shell=True) remove_file1.communicate() remove_file2 = subprocess.Popen(f'rm {ucs_filename}', stdout=subprocess.PIPE, shell=True) remove_file2.communicate() if True: # remove temp files and exit script remove_csv = subprocess.Popen(f'rm hosts.csv',
class Dns(): def __init__(self, dns_svr, user, password, csv_dns_dm): self.dns_svr = dns_svr self.user = user self.password = password self.csv_dns_fw_dm = csv_dns_dm[0] self.csv_dns_rv_dm = csv_dns_dm[1] # WSman connection used to run powershell cmds on windows servers self.wsman_conn = WSMan(self.dns_svr, username=self.user, password=self.password, ssl=False) self.client_conn = Client(self.dns_svr, username=self.user, password=self.password, ssl=False) ###################################### FAILFAST ###################################### # Check if zones exist on DNS server def failfast(self): all_zones, bad_zones = ([] for i in range(2)) # Create combined list of all forward and reverse zones for csv_dict in self.csv_dns_fw_dm: for zone in csv_dict.keys(): all_zones.append(zone) for csv_dict in self.csv_dns_rv_dm: for zone in csv_dict.keys(): all_zones.append(zone) # Interate through all zones and see if exist on DNS server for zone in all_zones: with RunspacePool(self.wsman_conn) as pool: print('-', zone) ps = PowerShell(pool) # The powershell cmd is "Get-DhcpServerv4Reservation -scopeid 192.168.200.0" ps.add_cmdlet("Invoke-Expression").add_parameter("Command", "Get-DnsServerZone {}".format(zone)) ps.add_cmdlet("Out-String").add_parameter("Stream") ps.invoke() dns_zones = ps.output if len(dns_zones) == 0: bad_zones.append(zone) # If any of the scopes dont not exist values are returned to main.py (which also casues script to exit) if len(bad_zones) != 0: return '!!! Error - The following zones dont exist on the DNS server: \n{}'.format(bad_zones) ###################################### Get DNS reservations ###################################### def get_entries(self): dns_fw_dm, dns_rv_dm = ([] for i in range(2)) # On a per-zone basis gets all the current DNS entries that will then be compared to those in the CSV for csv_dns_fw in self.csv_dns_fw_dm : for domain in csv_dns_fw.keys(): with RunspacePool(self.wsman_conn) as pool: ps = PowerShell(pool) # The powershell cmd is "Get-DnsServerResourceRecord -ZoneName stesworld.com -RRType A" ps.add_cmdlet("Invoke-Expression").add_parameter("Command", "Get-DnsServerResourceRecord -ZoneName {} -RRType A".format(domain)) ps.add_cmdlet("Out-String").add_parameter("Stream") ps.invoke() dns_fw_records = ps.output # From the ps output create a list for the dns_fw DM dict value [('ip', 'name', ttl)] ip_name_ttl = [] if len(dns_fw_records) == 0: # skips if no A records in the zone pass else: for a in dns_fw_records[3:-2]: # Elimates headers and trailing blank lines a = a.split() ip_name_ttl .append((a[-1], a[0].lower(), a[-2])) # Add the list as the value for for a dict where the zone name is the key [{fw_zone: [(ip, name, ttl)]}] dns_fw_dm.append({domain: ip_name_ttl}) # On a per-reverse-zone basis gets all the current DNS entries that will then be compared to those in the CSV for csv_dns_rv in self.csv_dns_rv_dm: for rev_zone in csv_dns_rv.keys(): with RunspacePool(self.wsman_conn) as pool: ps = PowerShell(pool) ps.add_cmdlet("Invoke-Expression").add_parameter("Command", "Get-DnsServerResourceRecord -ZoneName {} -RRType PTR".format(rev_zone)) ps.add_cmdlet("Out-String").add_parameter("Stream") ps.invoke() dns_rv_records = ps.output hst_name = [] if len(dns_rv_records) == 0: # skips if no PTR records in the zone pass else: for ptr in dns_rv_records[3:-2]: ptr = ptr.split() hst_name.append((ptr[0], ptr[-1].lower())) dns_rv_dm.append({rev_zone: hst_name}) # creates DM where rv_zone name is the key [{rv_zone: [(host, domain_name)]}] return [dns_fw_dm, dns_rv_dm] ###################################### Compare new Vs current resv ###################################### def verify_csv_vs_svr(self, dns_dm): dns_fw_dm = dns_dm[0] dns_rv_dm = dns_dm[1] csv_name, csv_rv_name, dns_fw_name, dns_rv_name, used_fw_fqdn, used_rv_fqdn = ([] for i in range(6)) # Create a list tuples of all FQDNs from CSV DMs (zone, fqdn) for dict_domain in self.csv_dns_fw_dm: domain = '.' + list(dict_domain.keys())[0] for all_values in dict_domain.values(): for each_value in all_values: csv_name.append((list(dict_domain.keys())[0], each_value[1] + domain)) for dict_domain in self.csv_dns_rv_dm: for all_values in dict_domain.values(): for each_value in all_values: csv_rv_name.append((list(dict_domain.keys())[0], each_value[1])) # Create a list tuples of all FQDNs from DNS DMs (zone, fqdn) for dict_domain in dns_fw_dm: domain = '.' + list(dict_domain.keys())[0] for all_values in dict_domain.values(): for each_value in all_values: dns_fw_name.append((list(dict_domain.keys())[0], each_value[1] + domain)) for dict_domain in dns_rv_dm: for all_values in dict_domain.values(): for each_value in all_values: dns_rv_name.append((list(dict_domain.keys())[0], each_value[1])) # Create list of any already used FQDNs in DNS by removing any unique values used_fw_fqdn = set(csv_name) & set(dns_fw_name) used_rv_fqdn = set(csv_rv_name) & set(dns_rv_name) used_fqdn = sorted(list(used_fw_fqdn)) + sorted(list(used_rv_fqdn)) # Compares FQDNs in CSV to FQDNs on DNS server, will list any in the CSV that are missing from DNS server missing_fw_fqdn = set(csv_name) - set(dns_fw_name) missing_rv_fqdn = set(csv_rv_name) - set(dns_rv_name) missing_fqdn = sorted(list(missing_fw_fqdn)) + sorted(list(missing_rv_fqdn)) # What is returned to main.py to kill script if any duplicates. len(csv_name) is used to compare pre and post number of entries len_csv = str(len(dns_fw_name)) + '/' + str(len(dns_rv_name)) # Number of added records in the format A/PTR output = {'len_csv': len_csv, 'used_entries': used_fqdn, 'missing_entries': missing_fqdn} return output ###################################### Creates new CSV with no scope prefix ###################################### def create_new_csv(self, type, csv_file, temp_csv): self.num_new_entries = 0 # Creates a temp csv file with header and format compatible with DNS server import. if type == 'add': with open(temp_csv, 'w') as x: writer = csv.writer(x) writer.writerow(['ZoneName','Name','IPAddress','TimeToLive']) for dict_domain in self.csv_dns_fw_dm: domain = list(dict_domain.keys())[0] for all_values in dict_domain.values(): for each_value in all_values: self.num_new_entries += 1 # Number of reservatiosn to be added writer.writerow([domain,each_value[1],each_value[0],each_value[2]]) # Dont add header on these as windows ps cmd wont understand 'ZoneName', luckily can do on position number so no need for header. elif type == 'remove': self.temp_csv1 = temp_csv.replace(".csv", "1.csv") # Extra temp file required for removing DNS RV entries with open(temp_csv, 'w') as x: writer = csv.writer(x) writer.writerow(['ZoneName','Name', 'RRType']) for dict_domain in self.csv_dns_fw_dm: domain = list(dict_domain.keys())[0] for all_values in dict_domain.values(): for each_value in all_values: self.num_new_entries += 1 # Number of reservatiosn to be added writer.writerow([domain,each_value[1],'A']) with open(self.temp_csv1, 'w') as x: writer = csv.writer(x) writer.writerow(['ZoneName','Name', 'RRType']) for dict_domain in self.csv_dns_rv_dm: domain = list(dict_domain.keys())[0] for all_values in dict_domain.values(): for each_value in all_values: writer.writerow([domain,each_value[0],'PTR']) # Used only with pytest to test new CSV file created and the contents are correct pytest_csv = [] with open(temp_csv, 'r') as x: csv_read = csv.reader(x) for row in csv_read: pytest_csv.append(row) if type == 'remove': # To test both CSVs if remove pytest_csv1 = [] with open(self.temp_csv1, 'r') as x: csv_read = csv.reader(x) for row in csv_read: pytest_csv1.append(row) return [pytest_csv, pytest_csv1] else: return pytest_csv ###################################### Adds or Removes the DHCP reservations ###################################### def deploy_csv(self, type, temp_csv, win_dir): win_dir1 = win_dir.replace(".csv", "1.csv") # Extra temp file required for removing DNS RV entries self.num_new_entries = str(self.num_new_entries) + '/' + str(self.num_new_entries) # To make it A/PTR records, should be same as deployed in the 1 cmd # Copy the new CSV File onto DHCP server, script will fail if it cant try: self.client_conn.copy(temp_csv, win_dir) if type == 'remove': self.client_conn.copy(self.temp_csv1, win_dir1) except Exception as e: # If copy fails script fails print("!!! Error - Could not copy CSV file to DNS server, investigate the below error before re-running the script.\n{}".format(e)) exit() # Add DNS entries if type == 'add': with RunspacePool(self.wsman_conn) as pool: ps = PowerShell(pool) ps.add_cmdlet("Import-Csv").add_argument("{}".format(win_dir)).add_cmdlet("Add-DNSServerResourceRecordA").add_parameter("-CreatePtr") ps.invoke() output = [self.num_new_entries, [ps.had_errors], [ps.streams.error]] # Remove DNS entries, have to spilt into multiple cmds due to bug with "Remove-DNSServerResourceRecord" where cant use RRtype from CSV elif type == 'remove': with RunspacePool(self.wsman_conn) as pool: ps = PowerShell(pool) ps.add_cmdlet("Import-Csv").add_argument("{}".format(win_dir)).add_cmdlet("Remove-DNSServerResourceRecord").add_parameter("RRtype", "A").add_parameter("-Force") ps.invoke() output = [self.num_new_entries, [ps.had_errors], [ps.streams.error]] # adds the errors as lists so can add outputs from next cmd with RunspacePool(self.wsman_conn) as pool: ps = PowerShell(pool) ps.add_cmdlet("Import-Csv").add_argument("{}".format(win_dir1)).add_cmdlet("Remove-DNSServerResourceRecord").add_parameter("RRtype", "PTR").add_parameter("-Force") ps.invoke() output[1].append(ps.had_errors) output[2].append(ps.streams.error) # Cleanup temp files try: os.remove(temp_csv) self.client_conn.execute_cmd("del {}".format(win_dir.replace("/", "\\"))) # Windows wont take / format with the cmd if type == 'remove': os.remove(self.temp_csv1) self.client_conn.execute_cmd("del {}".format(win_dir1.replace("/", "\\"))) # Windows wont take / format with the cmd except Exception as e: # If delete fails warns user print("!!! Warning - Could not delete temporary files off DNS server, you will have to do manually.\n{}".format(e)) return output
import pypsrp from pypsrp.client import Client if True: # set global variables now = datetime.datetime.now() month = '{:02d}'.format(now.month) day = '{:02d}'.format(now.day) device_hostname = '''+DEVICE HOSTNAME HERE+''' user = r'''+MS CA USERNAME WITH DOMAIN HERE+''' pwd = '''+MS CA PASSWORD HERE+''' ca = '''+MS CA IP OR RESOLVABLE HOSTNAME HERE+''' date_format = f'{now.year}{month}{day}' csrname = f'{device_hostname}_{now.year}{month}{day}.txt' ca_drive = r'''+PATH TO DRIVE WHERE CERTIFICATES ARE MANAGED ON MS CA HERE+''' submit_command = 'certreq.exe -submit -config -' certname = f'{now.year}{month}{day}.cer' if True: # set pypsrp client connection settings to CA ca_client = Client(f"{ca}", username=f"{user}", password=pwd, cert_validation=False, ssl=False) if True: # copy csr to CA with pypsrp client # !!!applicable csr must be present in directory where this is run!!! ca_client.copy(csrname, f"{ca_drive}\\{csrname}") if True: # 'submit'/sign csr on CA with pypsrp client ca_client.execute_cmd( f'{submit_command} {ca_drive}\\{csrname} {ca_drive}\\{certname}') if True: # fetch cert from CA # !!!will put certificate in directory where this is run!!! ca_client.fetch(f"{ca_drive}\\{certname}", certname)
import os from pypsrp.client import Client username = os.environ["ANSIBLE_WIN_USER"] password = os.environ["ANSIBLE_WIN_PASSWORD"] print(username) print(password) # this takes in the same kwargs as the WSMan object client = Client("localhost", port=5985, ssl=False, cert_validation=False, username=username, password=password) # execute a cmd command stdout, stderr, rc = client.execute_cmd("dir") print(stdout) stdout, stderr, rc = client.execute_cmd("powershell.exe gci $pwd") print(stderr) exit() sanitised_stderr = client.sanitise_clixml(stderr) # execute a PowerShell script output, streams, had_errors = client.execute_ps('''$path = "%s" if (Test-Path -Path $path) { Remove-Item -Path $path -Force -Recurse } New-Item -Path $path -ItemType Directory''' % path) output, streams, had_errors = client.execute_ps("New-Item -Path C:\\temp\\folder -ItemType Directory") # copy a file from the local host to the remote host client.copy("~/file.txt", "C:\\temp\\file.txt") # fetch a file from the remote host to the local host client.fetch("C:\\temp\\file.txt", "~/file.txt")
async def exec_powershell_script_dependencies(self, hosts, shell_type, arguments, dependency_folder, destination_folder, username, password, transport, server_cert_validation, message_encryption): """ Execute a list of remote commands on a list of hosts. :param hosts: List of host ips to run command on :param shell_type: The type of shell you wish to run (i.e. "powershell") :param commands: array of commands in which you want to run on every host :param dependency_folder: Specifies the local folder to copy :param destination_folder: Specifies the destination folder to copy and delete :param username: username of the machine you wish to run command on :param password: password for the machine you wish to run command on :param transport: method of transportation :param server_cert_validation: whether or not to verify certificates :param message_encryption: When you should encrypt messages :return: dict of results with hosts as keys and list of outputs for each specified hosts """ results = {} for host in hosts: self.logger.info(f"Connecting to {host}") results[host] = [] try: wsman = WSMan(host, ssl=server_cert_validation, auth=transport, encryption=message_encryption, username=username, password=password) client = Client(host, ssl=server_cert_validation, auth=transport, encryption=message_encryption, username=username, password=password) self.logger.info(f"Copying to {host}") for root, dirs, files in os.walk(dependency_folder): root_folder = destination_folder + "\\" + os.path.basename( root) output, streams, had_errors = client.execute_ps(''' $path = "%s" if(!(Test-Path -Path $path )){ New-Item -ItemType directory -Path $path Write-Host "New folder created" }''' % root_folder) results[host].append({ "stdout": output, "had_errors": had_errors }) for file in files: client.copy(os.path.join(root, file), root_folder + "\\" + file) self.logger.info(f"Executing on {host}") # execute scripts with WinRS(wsman) as shell: #Changes directory to dependency root and appends folder removal to end arguments = f"cd {destination_folder};" + '; '.join( arguments) self.logger.info(f"{arguments}") process = Process(shell, shell_type, [arguments]) process.invoke() results[host].append({ "stdout": process.stdout.decode(), "stderr": process.stderr.decode() }) arguments = f"Remove-Item -Recurse {destination_folder}" self.logger.info(f"Removing from {host}") process = Process(shell, shell_type, [arguments]) process.invoke() process.signal(SignalCode.CTRL_C) except Exception as e: import traceback tb = traceback.format_exc() results[host].append({ "stdout": "", "stderr": f"{e}", "exception": f"{tb}" }) return results
class Dhcp(): def __init__(self, dhcp_svr, user, password, csv_dhcp_dm): self.dhcp_svr = dhcp_svr self.user = user self.password = password self.csv_dhcp_dm = csv_dhcp_dm # WSman connection used to run powershell cmds on windows servers self.wsman_conn = WSMan(self.dhcp_svr, username=self.user, password=self.password, ssl=False) self.client_conn = Client(self.dhcp_svr, username=self.user, password=self.password, ssl=False) ###################################### FAILFAST ###################################### # Check if scopes exist on DHCP server def failfast(self): bad_scopes = [] for csv_dict in self.csv_dhcp_dm: for scope in csv_dict.keys(): print('-', scope) # Get list of all reservations in the scope with RunspacePool(self.wsman_conn) as pool: ps = PowerShell(pool) # The powershell cmd is "Get-DhcpServerv4Reservation -scopeid 192.168.200.0" ps.add_cmdlet("Invoke-Expression").add_parameter( "Command", "Get-DhcpServerv4Scope -scopeid {}".format(scope)) ps.add_cmdlet("Out-String").add_parameter("Stream") ps.invoke() dhcp_reserv = ps.output if len(dhcp_reserv) == 0: bad_scopes.append(scope) # If any of the scopes dont not exist values are returned to main.py (which also casues script to exit) if len(bad_scopes) != 0: return '!!! Error - The following scopes dont exist on the DHCP server: \n{}'.format( bad_scopes) ###################################### Get DHCP reservations ###################################### def get_entries(self): dhcp_dm = [] # On a per-scope gets all the current DHCP addresses that will then be compared to those in the CSV for csv_dict in self.csv_dhcp_dm: for scope in csv_dict.keys(): # Get list of all reservations in the scope with RunspacePool(self.wsman_conn) as pool: ps = PowerShell(pool) # The powershell cmd is "Get-DhcpServerv4Reservation -scopeid 192.168.200.0" ps.add_cmdlet("Invoke-Expression").add_parameter( "Command", "Get-DhcpServerv4Reservation -scopeid {}".format( scope)) ps.add_cmdlet("Out-String").add_parameter("Stream") ps.invoke() dhcp_reserv = ps.output[ 3:-2] # Elimates headers and blank lines # From the ps output create a DHCP DM of scope: [[IP], [mac], [name], [(IP, MAC, name)]] ip_name_mac = [] if len(dhcp_reserv ) == 0: # skips if no DHCP reservations in the scope pass else: for r in dhcp_reserv: ip_name_mac.append( (r.split()[0], r.split()[3][:17].lower(), r.split()[2].lower())) dhcp_dm.append({scope: ip_name_mac}) return dhcp_dm ###################################### Compare new Vs current resv ###################################### def verify_csv_vs_svr(self, dhcp_dm): csv_ip, csv_name, csv_mac, dhcp_ip, dhcp_name, dhcp_mac, dhcp_ip_name_mac = ( [] for i in range(7)) #Create a list of IPs, domain names and MACs from each DM (CSV and from dhcp_srv) for dict_scope in self.csv_dhcp_dm: for all_values in dict_scope.values(): for each_value in all_values: csv_ip.append(each_value[0]) csv_name.append( each_value[1][:17] ) # Needed as windows limits name returned to 17 characters csv_mac.append(each_value[2]) for dict_scope in dhcp_dm: for all_values in dict_scope.values(): for each_value in all_values: dhcp_ip.append(each_value[0]) dhcp_name.append(each_value[1]) dhcp_mac.append(each_value[2]) dhcp_ip_name_mac.append( each_value) # Used in user output if conflicts # Create list of any already used IPs, names or macs in reservations by removing any unique values used_ipadd = set(csv_ip) & set(dhcp_ip) used_name = set(csv_name) & set(dhcp_name) used_mac = set(dhcp_mac) & set(csv_mac) # Creates a list of all used reservations by finding it based on IP, name and mac in original DHCP reservations variable list_from_ip, list_from_name, list_from_mac = ([] for i in range(3)) if used_ipadd != 0: for x in used_ipadd: for y in dhcp_ip_name_mac: if x == y[0]: list_from_ip.append(y) if used_name != 0: for x in used_name: for y in dhcp_ip_name_mac: if x == y[1]: list_from_name.append(y) if used_mac != 0: for x in used_mac: for y in dhcp_ip_name_mac: if x == y[2]: list_from_mac.append(y) # Creates a final list of used reservations removing any duplicates from the ip, name and mac lists used_reserv = set(list_from_ip) | set(list_from_name) | set( list_from_mac) # Compares IPs in CSV to IPs on DHCP server, will list any in the CSV that are missing from DHCP server missing_resv = set(csv_ip) - set(dhcp_ip) # What is returned to main.py to kill script if any duplicates. len(csv_name) is used to compare pre and post number of entries output = { 'len_csv': len(dhcp_ip_name_mac), 'used_entries': sorted(list(used_reserv)), 'missing_entries': sorted(list(missing_resv)) } return output ###################################### Creates new CSV with no scope prefix ###################################### def create_new_csv(self, type, csv_file, temp_csv): # # Creates a new list from the CSV with prefix removed from the scope new_csv = [] with open(csv_file, 'r') as x: csv_read = csv.reader(x) for row in csv_read: if len(row) == 0 or all( 0 == len(s) for s in row ): #If it is a blank line skips or all blank columns continue else: row[0] = (row[0].split('/')[0] ) # Removes prefix from the scope new_csv.append(row) self.num_new_entries = len( new_csv) - 1 # Number of reservatiosn to be added # Writes the new list to a temp csv file with open(temp_csv, 'w') as x: writer = csv.writer(x) for row in new_csv: writer.writerow(row) # Used only with pytest to test new CSV file created and the contents are correct pytest_csv = [] with open(temp_csv, 'r') as x: csv_read = csv.reader(x) for row in csv_read: pytest_csv.append(row) return pytest_csv ###################################### Adds or Removes the DHCP reservations ###################################### def deploy_csv(self, type, temp_csv, win_dir): # Copy the new CSV File onto DHCP server, script will fail if it cant try: self.client_conn.copy(temp_csv, win_dir) except Exception as e: # If copy fails script fails print( "!!! Error - Could not copy CSV file to DHCP server, investigate the below error before re-running the script.\n{}" .format(e)) exit() # Add or remove DHCP entries dependant on the value of the variable 'type' with RunspacePool(self.wsman_conn) as pool: ps = PowerShell(pool) if type == 'add': ps.add_cmdlet("Import-Csv").add_argument("{}".format( win_dir)).add_cmdlet("Add-DhcpServerv4Reservation") elif type == 'remove': ps.add_cmdlet("Import-Csv").add_argument("{}".format( win_dir)).add_cmdlet("Remove-DhcpServerv4Reservation") ps.invoke() output = [self.num_new_entries, [ps.had_errors], [ps.streams.error]] # Cleanup temp files os.remove(temp_csv) try: self.client_conn.execute_cmd("del {}".format( win_dir.replace( "/", "\\"))) # Windows wont take / format with the cmd except Exception as e: # If delete fails warns user print( "!!! Warning - Could not delete temporary file {} off DHCP server, you will have to do manually.\n{}" .format(win_dir, e)) return output