├── .gitignore ├── LICENSE ├── README.md ├── ansible ├── README.md └── plugins │ └── modules │ └── switch_port.py ├── powershell └── MikrotikPSwitchOS │ ├── MikrotikPSwitchOS.psd1 │ ├── MikrotikPSwitchOS.psm1 │ ├── README.md │ ├── private │ ├── Convert-MikrotikLinkSpeed.ps1 │ ├── Convert-MikrotikLinks.ps1 │ ├── Convert-MikrotikPoE.ps1 │ ├── Convert-MikrotikPoEHexCodes.ps1 │ ├── Convert-MikrotikSFP.ps1 │ ├── Convert-MikrotikVLAN.ps1 │ ├── Convert-MikrotikVLANConfig.ps1 │ ├── Convert-MikrotikVLANHexCodes.ps1 │ ├── ConvertFrom-ArrayToHex.ps1 │ ├── ConvertFrom-HexToArray.ps1 │ ├── ConvertFrom-HexToBinary.ps1 │ ├── ConvertFrom-HexToInt.ps1 │ ├── ConvertFrom-HexToString.ps1 │ ├── ConvertFrom-IntToHex.ps1 │ ├── ConvertFrom-MikrotikToJson.ps1 │ └── ConvertFrom-StringToHex.ps1 │ └── public │ ├── Get-MikrotikLinks.ps1 │ ├── Get-MikrotikPoE.ps1 │ ├── Get-MikrotikSFP.ps1 │ ├── Get-MikrotikTotalPorts.ps1 │ ├── Get-MikrotikVLANConfig.ps1 │ ├── Get-MikrotikVLANs.ps1 │ ├── Invoke-MikrotikRestMethod.ps1 │ ├── Set-MikrotikSwitchPort.ps1 │ └── Set-MikrotikVLAN.ps1 └── python └── mikrotik_switch_api.py /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ollie-galbraith/mikrotik_switch_api/0cac203a28973cca23e3a13e2d49a78c1a89b462/.gitignore -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 ollie-galbraith 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mikrotik SwitchOS API 2 | 3 | ### Built With 4 | ![PowerShell][powershell-badge] 5 | ![Python][python-badge] 6 | ![Ansible][ansible-badge] 7 | 8 | For a project that I'm working on I needed to have access to programatically and automatically update my SwitchOS config on the fly. After a little bit of digging it turns out that the backend of SwitchOS uses a fairly basic (but non-human readable) API (with some accompanying JavaScript). 9 | 10 | After lots of clicking buttons, changing text, and playing around with Firefox Debug panel, I have reverse engineered the API from hex and binary to integers and strings. At least I reverse engineered the main pages haha. 11 | 12 | This is a repo containing a Powershell Module and basic Python/Ansible code to make the correct calls to the API. 13 | 14 | ## Usage 15 | 16 | #### Powershell 17 | Refer to the [Powershell README.md](/powershell/MikrotikPSwitchOS/README.md) 18 | 19 | #### Python 20 | The Python code is a simple port of the Powershell, and has the same structure/function. I am still learning to get around Python, so please forgive any "non-pythonic" code that there might be, or the lack of a proper package. 21 | 22 | #### Ansible 23 | Refer to the [Ansible README.md](/ansible/README.md) 24 | 25 | ## FAQ 26 | 27 | #### How does the API work 28 | 29 | While I dont know the ins and outs of the inner workings of the API, there is enough information from the JSON-like responses depending on the request that its easy enough to reverse engineer. 30 | 31 | It is mostly hex numbers and bitmasks, which need to be converted to be able to read them as a human. Thanks to this [forum post](https://forum.mikrotik.com/viewtopic.php?t=172802) for the basic information to get going 32 | 33 | ## To Note 34 | This is a side project for me, and I have only manaaged to test the code on three switch models 35 | - [CRS328-24P-4S+RM](https://mikrotik.com/product/crs328_24p_4s_rm) 36 | - [CRS309-1G-8S+IN](https://mikrotik.com/product/crs309_1g_8s_in) 37 | - [CSS326-24G-2S+RM](https://mikrotik.com/product/CSS326-24G-2SplusRM) 38 | 39 | There are bound to be some bugs with the code. 40 | There is a possiblity that if an incorrect config is sent to the switch, it can corrupt and only be saved with a hard reboot. So please practice backups. 41 | 42 | [ansible-badge]: https://shields.io/badge/ansible-20232A?style=for-the-badge&logo=ansible&logoColor=ff5750 43 | [python-badge]: https://shields.io/badge/python-20232A?style=for-the-badge&logo=python&logoColor=61DAFB 44 | [powershell-badge]: https://shields.io/badge/powershell-20232A?style=for-the-badge&logo=powershell&logoColor=61DAFB 45 | [powershell-url]: https://learn.microsoft.com/en-us/powershell/ 46 | -------------------------------------------------------------------------------- /ansible/README.md: -------------------------------------------------------------------------------- 1 | # Ansible 2 | 3 | I wrote this small wrapper for Ansible so I could idempotentaly make changes to a Mikrotik Switch via Ansible 4 | 5 | ## Parameters 6 | 7 | | Parameter | Comments | 8 | | :-------- | :------- | 9 | | `auto_neg`
boolen | Enables or disables Auto-Negotiation for the switch port
`Choices:`
`false`
`true` | 10 | | `command_type`
string | Tells Ansible whether to run a "get" command or a "set" command
`Choices:`
`get (default)`
`set` | 11 | | `enabled`
boolen | Enables or disables the switch port
`Choices:`
`false`
`true` | 12 | | `output_only`
string | Returns the specified parameter
`Choices:`
`port_name`
`enabled`
`auto_neg` | 13 | | `port_name`
string | Name of the port | 14 | | `port_number`
integer | The port number to run the API call against | 15 | | `switch_password`
string | Password to give access to the switch | 16 | | `switch_url`
string | URL that the switch is accessed from | 17 | | `switch_username`
string | Username to give access to the switch | 18 | -------------------------------------------------------------------------------- /ansible/plugins/modules/switch_port.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from ansible.module_utils.basic import * 4 | import re 5 | import json 6 | import requests 7 | from requests.auth import HTTPDigestAuth 8 | 9 | def send_Mikrotik_Rest_Method(url, method, query, username, password, body=None): 10 | headers = { 11 | "Accept": "*/*", 12 | "Accept-Language": "en-US,en;q=0.5", 13 | "Accept-Encoding": "gzip, deflate", 14 | "Content-Type": "text/plain", 15 | "Origin": f"{url}", 16 | "Referer": f"{url}/index.html" 17 | } 18 | 19 | url = f"{url}/{query}" 20 | 21 | request_params = dict( 22 | method = method, 23 | url = url, 24 | headers = headers, 25 | auth = HTTPDigestAuth(username=username, password=password) 26 | ) 27 | 28 | if body != None: 29 | request_params['data'] = body 30 | 31 | response = requests.request(**request_params) 32 | return response.text 33 | 34 | def convert_Mikrotik_Json(input_object): 35 | json_dump = input_object 36 | 37 | word_regex = r"(\w+)" 38 | single_quote_regex = r"(\')" 39 | double_double_quote_regex = r'\"{2}(\w+)\"{2}' 40 | 41 | json_dump = re.sub(word_regex, r'"\1"', json_dump) 42 | json_dump = re.sub(single_quote_regex, r'"', json_dump) 43 | json_dump = re.sub(double_double_quote_regex, r'"\1"', json_dump) 44 | json_dump = re.sub('],}','}]', json_dump) 45 | 46 | json_output = json.loads(json_dump) 47 | 48 | return json_output 49 | 50 | def convert_Mikrotik_Array_Hex(array, padding=8): 51 | binary_string = str('') 52 | array.reverse() 53 | for item in array: 54 | if item == True: 55 | bin = '1' 56 | elif item == False: 57 | bin = '0' 58 | binary_string += bin 59 | 60 | padding = padding + 2 61 | hex_output = f"{int(binary_string, 2):#0{padding}x}" 62 | return hex_output 63 | 64 | def convert_Mikrotik_Link_Speed(hex_string): 65 | SwOS_link_speeds = { 66 | '0x01': 0.1, 67 | '0x02': 1.0, 68 | '0x07': 0.0, 69 | '0x04': 0.0, 70 | '0x03': 10.0 71 | } 72 | 73 | for speeds in SwOS_link_speeds: 74 | if speeds == hex_string: 75 | return SwOS_link_speeds[speeds] 76 | 77 | def convert_Mikrotik_Hex_Array(hex_string, pad_length): 78 | output = [] 79 | binary = f'{int(hex_string, 16):0>{pad_length}b}' 80 | for element in binary: 81 | if element == '1': 82 | output.append(True) 83 | else: 84 | output.append(False) 85 | output.reverse() 86 | return output 87 | 88 | def get_Mikrotik_Switch_Port(url, username, password, port_number=None, port_name=None, output_only=None): 89 | query = 'link.b' 90 | method = 'GET' 91 | response = send_Mikrotik_Rest_Method(url=url, query=query, method=method, username=username, password=password) 92 | links = convert_Mikrotik_Json(input_object=response) 93 | 94 | total_ports = int(links['prt'], 16) 95 | port_instance = 0 96 | output = [] 97 | 98 | enabled_ports = convert_Mikrotik_Hex_Array(hex_string=links['en'], pad_length=total_ports) 99 | link_active = convert_Mikrotik_Hex_Array(hex_string=links['lnk'] , pad_length=total_ports) 100 | auto_neg_ports = convert_Mikrotik_Hex_Array(hex_string=links['an'], pad_length=total_ports) 101 | duplex_ports = convert_Mikrotik_Hex_Array(hex_string=links['dpx'], pad_length=total_ports) 102 | 103 | while port_instance < total_ports: 104 | object = { 105 | 'enabled': enabled_ports[port_instance], 106 | 'port_number': port_instance + 1, 107 | 'port_name': bytes.fromhex(links['nm'][port_instance]).decode('utf-8'), 108 | 'link_speed': convert_Mikrotik_Link_Speed(hex_string=links['spd'][port_instance]), 109 | 'link_active': link_active[port_instance], 110 | 'auto_neg': auto_neg_ports[port_instance], 111 | 'full_duplex': duplex_ports[port_instance], 112 | } 113 | port_instance += 1 114 | output.append(object) 115 | 116 | output_options = ( 117 | 'port_name', 118 | 'enabled', 119 | 'auto_neg' 120 | ) 121 | 122 | result = [] 123 | if output_only in output_options: 124 | for item in output: 125 | result.append(item[output_only]) 126 | else: 127 | if port_number != None: 128 | result = output[port_number - 1] 129 | elif port_name != None: 130 | for ports in output: 131 | if ports['port_name'] == port_name: 132 | result.append(ports) 133 | else: 134 | result = output 135 | 136 | return result 137 | 138 | def set_Mikrotik_Switch_Port(url, username, password, port_number, port_name=None, enabled=True, auto_neg=True): 139 | query = 'link.b' 140 | response = send_Mikrotik_Rest_Method(url=url, query=query, method='GET', username=username, password=password) 141 | mikrotik_config = convert_Mikrotik_Json(input_object=response) 142 | 143 | new_mikrotik_config = '' 144 | name_count = 1 145 | speed_count = 1 146 | 147 | get_Mikrotik_Link_params = dict( 148 | url = url, 149 | username = username, 150 | password = password 151 | ) 152 | 153 | port_names = get_Mikrotik_Switch_Port(**get_Mikrotik_Link_params, output_only='port_name') 154 | port_enabled = get_Mikrotik_Switch_Port(**get_Mikrotik_Link_params, output_only='enabled') 155 | port_auto_neg = get_Mikrotik_Switch_Port(**get_Mikrotik_Link_params, output_only='auto_neg') 156 | 157 | array_port_number = port_number - 1 158 | #print(mikrotik_config) 159 | if port_name != None: 160 | new_port_name = port_name 161 | if new_port_name not in port_names: 162 | new_port_name_hex = new_port_name.encode('utf-8').hex() 163 | mikrotik_config['nm'][array_port_number] = new_port_name_hex 164 | 165 | if port_enabled[array_port_number] != enabled: 166 | new_port_enabled = list(port_enabled) 167 | new_port_enabled[array_port_number] = enabled 168 | 169 | new_port_enabled_hex = convert_Mikrotik_Array_Hex(array=new_port_enabled) 170 | mikrotik_config['en'] = new_port_enabled_hex 171 | 172 | if port_auto_neg[array_port_number] != auto_neg: 173 | new_port_auto_neg = list(port_auto_neg) 174 | new_port_auto_neg[array_port_number] = auto_neg 175 | 176 | new_port_auto_neg_hex = convert_Mikrotik_Array_Hex(array=new_port_auto_neg) 177 | mikrotik_config['an'] = new_port_auto_neg_hex 178 | 179 | new_mikrotik_config += f"{{en:{mikrotik_config['en']},nm:[" 180 | for name_hex in mikrotik_config['nm']: 181 | if name_count <= (len(mikrotik_config['nm']) - 1): 182 | new_mikrotik_config += f"'{name_hex}'," 183 | name_count += 1 184 | else: 185 | new_mikrotik_config += f"'{name_hex}'" 186 | new_mikrotik_config += f"],an:{mikrotik_config['an']},spdc:[" 187 | for speed_hex in mikrotik_config['spdc']: 188 | if speed_count <= (len(mikrotik_config['spdc']) - 1): 189 | new_mikrotik_config += f"'{speed_hex}'," 190 | speed_count += 1 191 | else: 192 | new_mikrotik_config += f"'{speed_hex}'" 193 | new_mikrotik_config += f"],dpxc:{mikrotik_config['dpxc']},fctc:{mikrotik_config['fctc']},fctr:{mikrotik_config['fctr']}}}" 194 | 195 | send_Mikrotik_Rest_Method(url=url, query=query, method='POST', username=username, password=password, body=new_mikrotik_config) 196 | 197 | def ports(): 198 | module_args = dict( 199 | switch_url=dict(type='str', required=True), 200 | switch_username=dict(type='str', required=True), 201 | switch_password=dict(type='str', required=True, no_log=True), 202 | command_type=dict( 203 | type='str', 204 | required=False, 205 | choices = ['get','set'], 206 | default='get'), 207 | port_name=dict(type='str', required=False), 208 | port_number=dict(type='int', required=False), 209 | enabled=dict(type='bool', required=False), 210 | auto_neg=dict(type='bool', required=False), 211 | output_only=dict( 212 | type='str', 213 | required=False, 214 | choices = ['port_name','enabled','auto_neg']) 215 | ) 216 | 217 | result = dict( 218 | changed = False, 219 | original_message = '', 220 | ports = '' 221 | ) 222 | 223 | module = AnsibleModule( 224 | argument_spec = module_args, 225 | supports_check_mode = True 226 | ) 227 | 228 | if module.check_mode: 229 | module.exit_json(**result) 230 | 231 | get_mikrotik_switch_port_params = dict( 232 | url = module.params['switch_url'], 233 | username = module.params['switch_username'], 234 | password = module.params['switch_password'] 235 | ) 236 | 237 | set_mikrotik_switch_port_params = dict(get_mikrotik_switch_port_params) 238 | 239 | if module.params['port_number'] is not None and module.params['command_type'] == 'set': 240 | get_mikrotik_switch_port_params['port_number'] = module.params['port_number'] 241 | original_config = get_Mikrotik_Switch_Port(**get_mikrotik_switch_port_params) 242 | 243 | set_mikrotik_switch_port_params['port_number'] = module.params['port_number'] 244 | 245 | if module.params['port_name'] is not None: 246 | set_mikrotik_switch_port_params['port_name'] = module.params['port_name'] 247 | result['prev_port_name'] = original_config['port_name'] 248 | 249 | if module.params['enabled'] is not None: 250 | set_mikrotik_switch_port_params['enabled'] = module.params['enabled'] 251 | result['prev_port_enabled_state'] = original_config['enabled'] 252 | 253 | if module.params['auto_neg'] is not None: 254 | set_mikrotik_switch_port_params['auto_neg'] = module.params['auto_neg'] 255 | result['prev_port_auto_neg_state'] = original_config['auto_neg'] 256 | 257 | set_Mikrotik_Switch_Port(**set_mikrotik_switch_port_params) 258 | output = get_Mikrotik_Switch_Port(**get_mikrotik_switch_port_params) 259 | result['changed'] = True 260 | 261 | 262 | elif module.params['port_number'] is not None and module.params['command_type'] == 'get': 263 | get_mikrotik_switch_port_params['port_number'] = module.params['port_number'] 264 | output = get_Mikrotik_Switch_Port(**get_mikrotik_switch_port_params) 265 | 266 | elif module.params['port_name'] is not None: 267 | get_mikrotik_switch_port_params['port_name'] = module.params['port_name'] 268 | output = get_Mikrotik_Switch_Port(**get_mikrotik_switch_port_params) 269 | 270 | elif module.params['output_only'] is not None: 271 | get_mikrotik_switch_port_params['output_only'] = module.params['output_only'] 272 | output = get_Mikrotik_Switch_Port(**get_mikrotik_switch_port_params) 273 | 274 | else: 275 | output = get_Mikrotik_Switch_Port(**get_mikrotik_switch_port_params) 276 | 277 | result['ports'] = output 278 | module.exit_json(**result) 279 | 280 | def main(): 281 | ports() 282 | 283 | if __name__ == '__main__': 284 | main() -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/MikrotikPSwitchOS.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'MikrotikPSwitchOS' 3 | # 4 | # Generated by: Oliver Galbraith 5 | # 6 | # Generated on: 03/05/2023 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'MikrotikPSwitchOS.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.0.1.5' 16 | 17 | # Supported PSEditions 18 | # CompatiblePSEditions = @() 19 | 20 | # ID used to uniquely identify this module 21 | GUID = '9a053f09-191c-43d9-af9b-27f1ab9a1bd4' 22 | 23 | # Author of this module 24 | Author = 'Oliver Galbraith' 25 | 26 | # Company or vendor of this module 27 | CompanyName = 'Oliver Galbraith' 28 | 29 | # Copyright statement for this module 30 | Copyright = '(c) 2023 Oliver Galbraith. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | Description = 'Hooks into the API behind Mikrotik SwitchOS to allow for automating switch processes through PowerShell' 34 | 35 | # Minimum version of the Windows PowerShell engine required by this module 36 | # PowerShellVersion = '' 37 | 38 | # Name of the Windows PowerShell host required by this module 39 | # PowerShellHostName = '' 40 | 41 | # Minimum version of the Windows PowerShell host required by this module 42 | # PowerShellHostVersion = '' 43 | 44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 45 | # DotNetFrameworkVersion = '' 46 | 47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 48 | # CLRVersion = '' 49 | 50 | # Processor architecture (None, X86, Amd64) required by this module 51 | # ProcessorArchitecture = '' 52 | 53 | # Modules that must be imported into the global environment prior to importing this module 54 | #RequiredModules = @() 55 | 56 | # Assemblies that must be loaded prior to importing this module 57 | # RequiredAssemblies = @() 58 | 59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 60 | # ScriptsToProcess = @() 61 | 62 | # Type files (.ps1xml) to be loaded when importing this module 63 | # TypesToProcess = @() 64 | 65 | # Format files (.ps1xml) to be loaded when importing this module 66 | #FormatsToProcess = @() 67 | 68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 69 | # NestedModules = @() 70 | 71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 72 | FunctionsToExport = @('*') 73 | 74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 75 | CmdletsToExport = @() 76 | 77 | # Variables to export from this module 78 | VariablesToExport = '*' 79 | 80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 81 | AliasesToExport = @() 82 | 83 | # DSC resources to export from this module 84 | # DscResourcesToExport = @() 85 | 86 | # List of all modules packaged with this module 87 | # ModuleList = @() 88 | 89 | # List of all files packaged with this module 90 | # FileList = @() 91 | 92 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 93 | PrivateData = @{ 94 | 95 | PSData = @{ 96 | 97 | #ExternalModuleDependencies = @() 98 | 99 | # Tags applied to this module. These help with module discovery in online galleries. 100 | # Tags = @() 101 | 102 | # A URL to the license for this module. 103 | # LicenseUri = '' 104 | 105 | # A URL to the main website for this project. 106 | # ProjectUri = '' 107 | 108 | # A URL to an icon representing this module. 109 | # IconUri = '' 110 | 111 | # ReleaseNotes of this module 112 | # ReleaseNotes = '' 113 | 114 | } # End of PSData hashtable 115 | 116 | } # End of PrivateData hashtable 117 | 118 | # HelpInfo URI of this module 119 | # HelpInfoURI = '' 120 | 121 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 122 | # DefaultCommandPrefix = '' 123 | 124 | } 125 | 126 | -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/MikrotikPSwitchOS.psm1: -------------------------------------------------------------------------------- 1 | Get-ChildItem -Path $PSScriptRoot -Include *.ps1 -Recurse | ForEach-Object {. $_.FullName} 2 | $ExportedFunctions = Get-ChildItem -Path "$PSScriptRoot\Public\" | ForEach-Object {$_.Name -replace ".ps1"} 3 | Export-ModuleMember -Function $ExportedFunctions -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/README.md: -------------------------------------------------------------------------------- 1 | 2 | # PowerShell 3 | 4 | This is where this project started. I knew that eventually this would have to run with something like Python, however I'm still fairly new to Python, so I thought I would proof of concept everything in Powershell first. 5 | 6 | 7 | 8 | ## Installation 9 | 10 | To install, simply download the module files and install to your choice of paths in ```$env:PSModulePath``` 11 | 12 | ```powershell 13 | Copy-Item -Destination 14 | Import-Module MikrotikPSwitchOS 15 | ``` 16 | 17 | ## Usage/Examples 18 | 19 | #### Get-MikrotikLinks 20 | ```powershell 21 | PS C:\> $Credential = Get-Credential 22 | PS C:\> $URL = 'http://mikrotik-switch.url.com' 23 | 24 | PS C:\> Get-MikrotikLinks -Credential $Credential -URL $URL 25 | 26 | Enabled PortNumber PortType PortName LinkSpeed LinkActive AutoNeg FullDuplex 27 | ------- ---------- -------- -------- --------- ---------- ------- ---------- 28 | True 1 rj45 Router 1 True True True 29 | True 2 rj45 Port2 1 True True True 30 | True 3 rj45 Port3 1 True True True 31 | True 4 rj45 Port4 1 True True True 32 | True 5 rj45 Port5 0 False True False 33 | True 6 rj45 Port6 0 False True False 34 | True 7 rj45 Port7 0 False True False 35 | ... 36 | ``` 37 | 38 | #### Get-MikrotikSFP 39 | ```powershell 40 | PS C:\> $Credential = Get-Credential 41 | PS C:\> $URL = 'http://mikrotik-switch.url.com' 42 | 43 | PS C:\> Get-MikrotikSFP -Credential $Credential -URL $URL 44 | 45 | PortNumber PortName Vendor PartNumber Serial Type Temp Voltage 46 | ---------- -------- ------ ---------- ------ ---- ---- ------- 47 | 25 SFP1 MikroTik S+RJ10 HCR01V1VFSK 1m copper 83 3.272 48 | 26 SFP2 Ubiquiti Inc. UC-DAC-SFP+ AH22018007220 1m copper 0 0 49 | 27 SFP3 0 0 50 | 28 SFP4 0 0 51 | ``` 52 | 53 | #### Get-MikrotikVLANs 54 | ```powershell 55 | PS C:\> $Credential = Get-Credential 56 | PS C:\> $URL = 'http://mikrotik-switch.url.com' 57 | 58 | PS C:\> Get-MikrotikVLANs -Credential $Credential -URL $URL 59 | 60 | PortNumber PortName VLANMode VLANReceive VLANID ForceVLANID 61 | ---------- -------- -------- ----------- ------ ----------- 62 | 1 Router Optional Any 1 False 63 | 2 Port2 Optional Any 88 False 64 | 3 Port3 Optional Any 88 False 65 | 4 Port4 Optional Any 88 False 66 | 5 Port5 Optional Any 88 False 67 | 6 Port6 Optional Any 88 False 68 | 7 Port7 Optional Any 88 False 69 | ``` 70 | 71 | #### Set-MikroTikSwitchPort 72 | ```powershell 73 | PS C:\> $Credential = Get-Credential 74 | PS C:\> $URL = 'http://mikrotik-switch.url.com' 75 | 76 | PS C:\> Get-MikrotikLinks -Credential $Credential -URL $URL 77 | 78 | Enabled PortNumber PortType PortName LinkSpeed LinkActive AutoNeg FullDuplex 79 | ------- ---------- -------- -------- --------- ---------- ------- ---------- 80 | True 1 rj45 Router 1 True True True 81 | True 2 rj45 Port2 1 True True True 82 | True 3 rj45 Port3 1 True True True 83 | True 4 rj45 Port4 1 True True True 84 | True 5 rj45 Port5 0 False True False 85 | True 6 rj45 Port6 0 False True False 86 | True 7 rj45 Port7 0 False True False 87 | ... 88 | 89 | PS C:\> Set-MikrotikSwitchPort -PortNumber 6 -PortName Testing -Enabled $false -Credential $Credential -URL $URL 90 | PS C:\> Get-MikrotikLinks -Credential $Credential -URL $URL 91 | 92 | Enabled PortNumber PortType PortName LinkSpeed LinkActive AutoNeg FullDuplex 93 | ------- ---------- -------- -------- --------- ---------- ------- ---------- 94 | True 1 rj45 Router 1 True True True 95 | True 2 rj45 Port2 1 True True True 96 | True 3 rj45 Port3 1 True True True 97 | True 4 rj45 Port4 1 True True True 98 | True 5 rj45 Port5 0 False True False 99 | False 6 rj45 Testing 0 False True False 100 | True 7 rj45 Port7 0 False True False 101 | ... 102 | ``` 103 | 104 | #### Set-MikroTikVLAN 105 | ```powershell 106 | PS C:\> $Credential = Get-Credential 107 | PS C:\> $URL = 'http://mikrotik-switch.url.com' 108 | 109 | PS C:\> Get-MikrotikVLANs -Credential $Credential -URL $URL 110 | 111 | PortNumber PortName VLANMode VLANReceive VLANID ForceVLANID 112 | ---------- -------- -------- ----------- ------ ----------- 113 | 1 Router Optional Any 1 False 114 | 2 Port2 Optional Any 88 False 115 | 3 Port3 Optional Any 88 False 116 | 4 Port4 Optional Any 88 False 117 | 5 Port5 Optional Any 88 False 118 | 6 Port6 Optional Any 88 False 119 | 7 Port7 Optional Any 88 False 120 | ... 121 | 122 | PS C:\> Set-MikrotikVLAN -PortNumber 6 -VLANMode Disabled -VLANReceive 'Only Tagged' -VLANID 99 -Credential $Credential -URL $URL 123 | PS C:\> Get-MikrotikLinks -Credential $Credential -URL $URL 124 | 125 | PortNumber PortName VLANMode VLANReceive VLANID ForceVLANID 126 | ---------- -------- -------- ----------- ------ ----------- 127 | 1 Router Optional Any 1 False 128 | 2 Port2 Optional Any 88 False 129 | 3 Port3 Optional Any 88 False 130 | 4 Port4 Optional Any 88 False 131 | 5 Port5 Optional Any 88 False 132 | 6 Port6 Disabled Only Tagged 99 False 133 | 7 Port7 Optional Any 88 False 134 | ... 135 | ``` 136 | -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/Convert-MikrotikLinkSpeed.ps1: -------------------------------------------------------------------------------- 1 | Function Convert-MikrotikLinkSpeed 2 | { 3 | <# 4 | .Synopsis 5 | Converts the Mikrotik API output from hex to link speeds (in double) 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | $Hex 11 | ) 12 | 13 | $SwOSLinkSpeeds = @{ 14 | '0x01' = 0.1 15 | '0x02' = 1.0 16 | '0x07' = 0.0 17 | '0x04' = 0.0 18 | '0x03' = 10.0 19 | } 20 | 21 | ForEach($Speed in $SwOSLinkSpeeds.GetEnumerator()) 22 | { 23 | If($Speed.Key -eq $Hex) 24 | { 25 | Return $Speed.Value 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/Convert-MikrotikLinks.ps1: -------------------------------------------------------------------------------- 1 | Function Convert-MikrotikLinks 2 | { 3 | <# 4 | .Synopsis 5 | Converts the Mikrotik API link page output from hex to boolean arrays/plain text 6 | #> 7 | 8 | param( 9 | [PSCustomObject]$InputObject, 10 | [Int]$TotalPorts 11 | ) 12 | 13 | $Ports = $InputObject.nm.count 14 | $PortNumber = 0 15 | 16 | [array]$EnabledPorts = ConvertFrom-HexToArray -Hex $InputObject.en -ArrayLength $TotalPorts 17 | [array]$AutoNegPorts = ConvertFrom-HexToArray -Hex $InputObject.an -ArrayLength $TotalPorts 18 | [array]$DuplexPorts = ConvertFrom-HexToArray -Hex $InputObject.dpx -ArrayLength $TotalPorts 19 | [array]$LinkPorts = ConvertFrom-HexToArray -Hex $InputObject.lnk -ArrayLength $TotalPorts 20 | 21 | $TotalPorts = [uint32]$InputObject.prt 22 | $RJ45Ports = [uint32]$InputObject.sfpo 23 | 24 | [System.Collections.ArrayList]$Output = @() 25 | While($PortNumber -le ($Ports - 1)) 26 | { 27 | [double]$LinkSpeed = "$(Convert-MikrotikLinkSpeed -Hex $InputObject.spd[$PortNumber])" 28 | If(($PortNumber -lt $RJ45Ports) -or ($LinkSpeed -le 0.1)) 29 | { 30 | $Type = "rj45" 31 | } 32 | If(($PortNumber -ge $RJ45Ports) -and (($LinkSpeed -eq 0) -or ($LinkSpeed -gt 0.1))) 33 | { 34 | $Type = 'sfp' 35 | } 36 | $PortOptions = [pscustomObject]@{ 37 | Enabled = $EnabledPorts[$PortNumber] 38 | PortNumber = $PortNumber + 1 39 | PortType = $Type 40 | PortName = "$(ConvertFrom-HexToString -Hex $InputObject.nm[$PortNumber])" 41 | LinkSpeed = $LinkSpeed 42 | LinkActive = $LinkPorts[$PortNumber] 43 | AutoNeg = $AutoNegPorts[$PortNumber] 44 | FullDuplex = $DuplexPorts[$PortNumber] 45 | } 46 | [void]$Output.Add($PortOptions) 47 | $PortNumber += 1 48 | } 49 | Return $Output 50 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/Convert-MikrotikPoE.ps1: -------------------------------------------------------------------------------- 1 | Function Convert-MikrotikPoE 2 | { 3 | <# 4 | .Synopsis 5 | Converts the Mikrotik API PoE page output from hex to boolean arrays/plain text 6 | #> 7 | 8 | param( 9 | [PSCustomObject]$InputObject, 10 | [PSCustomObject]$Links, 11 | [int]$TotalPorts 12 | ) 13 | 14 | $Ports = $Links.count 15 | $PortNumber = 0 16 | 17 | [System.Collections.ArrayList]$Output = @() 18 | While($PortNumber -le ($Ports - 1)) 19 | { 20 | $Current = "$(ConvertFrom-HexToInt -Hex $InputObject.curr[$PortNumber])" 21 | [double]$DecimalCurrent = $Current.Insert(($Current.Length -1), '.') 22 | 23 | $Voltage = "$(ConvertFrom-HexToInt -Hex $InputObject.volt[$PortNumber])" 24 | [double]$DecimalVoltage = $Voltage.Insert(($Voltage.Length -1), '.') 25 | 26 | $Power = "$(ConvertFrom-HexToInt -Hex $InputObject.pwr[$PortNumber])" 27 | [double]$DecimalPower = $Power.Insert(($Power.Length -1), '.') 28 | 29 | $PortOptions = [pscustomObject]@{ 30 | PortNumber = $Links[$PortNumber].PortNumber 31 | PortName = $Links[$PortNumber].PortName 32 | PoEOut = "$(Convert-MikrotikPoeHexCodes -Type PoEOut -Hex $InputObject.poe[$PortNumber])" 33 | PoEPriority = ConvertFrom-HexToInt -Hex $InputObject.prio[$PortNumber] 34 | VoltageLevel = Convert-MikrotikPoeHexCodes -Type PoELevel -Hex $InputObject.lvl[$PortNumber] 35 | Status = Convert-MikrotikPoeHexCodes -Type PoEStatus -Hex $InputObject.poes[$PortNumber] 36 | Current = "$DecimalCurrent`mA" 37 | Voltage = "$DecimalVoltage`V" 38 | Power = "$DecimalPower`W" 39 | } 40 | [void]$Output.Add($PortOptions) 41 | $PortNumber += 1 42 | } 43 | Return $Output 44 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/Convert-MikrotikPoEHexCodes.ps1: -------------------------------------------------------------------------------- 1 | Function Convert-MikrotikPoeHexCodes 2 | { 3 | param( 4 | [ValidateSet('PoEOut','PoELevel','PoEStatus')] 5 | [Parameter(Mandatory=$true)] 6 | $Type, 7 | [Parameter(Mandatory=$true, ParameterSetName='Hex')] 8 | $Hex, 9 | [Parameter(Mandatory=$true, ParameterSetName='String')] 10 | [String]$String 11 | ) 12 | 13 | Switch($Type) 14 | { 15 | PoeOut 16 | { 17 | $Hashtable = @{ 18 | '0x00' = 'Off' 19 | '0x01' = 'On' 20 | '0x02' = 'Auto' 21 | } 22 | } 23 | PoELevel 24 | { 25 | $Hashtable = @{ 26 | '0x00' = 'Auto' 27 | '0x01' = 'Low' 28 | '0x02' = 'High' 29 | } 30 | } 31 | PoEStatus 32 | { 33 | $Hashtable = @{ 34 | '0x00' = 'No PoE' 35 | '0x02' = 'Waiting for Load' 36 | '0x03' = 'Powered On' 37 | '0x05' = 'Short Circuit' 38 | } 39 | } 40 | } 41 | ForEach($Code in $Hashtable.GetEnumerator()) 42 | { 43 | If($Hex -ne '') 44 | { 45 | If($Code.Key -eq $Hex) 46 | { 47 | Return $Code.Value 48 | } 49 | } 50 | If($String -ne '') 51 | { 52 | If($Code.Value -eq $String) 53 | { 54 | Return $Code.Key 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/Convert-MikrotikSFP.ps1: -------------------------------------------------------------------------------- 1 | Function Convert-MikrotikSFP 2 | { 3 | <# 4 | .Synopsis 5 | Converts the Mikrotik API SPF pages output from hex to boolean arrays/plain text 6 | #> 7 | 8 | param( 9 | [PSCustomObject]$InputObject, 10 | [PSCustomObject]$Links 11 | ) 12 | 13 | $Ports = $Links.count 14 | $PortNumber = 0 15 | 16 | [System.Collections.ArrayList]$Output = @() 17 | While($PortNumber -le ($Ports - 1)) 18 | { 19 | [int64]$Temp = "$([uint32]$InputObject.tmp[$PortNumber])" 20 | [double]$Voltage = "$((([uint32]$InputObject.vcc[$PortNumber]).ToString()).Insert(1,'.'))" 21 | 22 | If($Temp -gt 150) 23 | { 24 | $Temp = $null 25 | } 26 | If($Voltage -gt 5.0) 27 | { 28 | $Voltage = $null 29 | } 30 | 31 | $PortOptions = [pscustomObject]@{ 32 | PortNumber = $Links[$PortNumber].PortNumber 33 | PortName = $Links[$PortNumber].PortName 34 | Vendor = "$(ConvertFrom-HexToString -Hex $InputObject.vnd[$PortNumber])" 35 | PartNumber = "$(ConvertFrom-HexToString -Hex $InputObject.pnr[$PortNumber])" 36 | Serial = "$(ConvertFrom-HexToString -Hex $InputObject.ser[$PortNumber])" 37 | Type = "$(ConvertFrom-HexToString -Hex $InputObject.typ[$PortNumber])" 38 | Temp = $Temp 39 | Voltage = $Voltage 40 | } 41 | [void]$Output.Add($PortOptions) 42 | $PortNumber += 1 43 | } 44 | Return $Output 45 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/Convert-MikrotikVLAN.ps1: -------------------------------------------------------------------------------- 1 | Function Convert-MikrotikVLAN 2 | { 3 | <# 4 | .Synopsis 5 | Converts the Mikrotik API VLAN page output from hex to boolean arrays/plain text 6 | #> 7 | 8 | param( 9 | [PSCustomObject]$InputObject, 10 | [PSCustomObject]$Links, 11 | [int]$TotalPorts 12 | ) 13 | 14 | $Ports = $Links.count 15 | $PortNumber = 0 16 | 17 | [array]$ForceVLAN = ConvertFrom-HexToArray -Hex $InputObject.fvid -ArrayLength $TotalPorts 18 | 19 | [System.Collections.ArrayList]$Output = @() 20 | While($PortNumber -le ($Ports - 1)) 21 | { 22 | $PortOptions = [pscustomObject]@{ 23 | PortNumber = $Links[$PortNumber].PortNumber 24 | PortName = $Links[$PortNumber].PortName 25 | VLANMode = "$(Convert-MikrotikVLANHexCodes -Type VLANMode -Hex $InputObject.vlan[$PortNumber])" 26 | VLANReceive = "$(Convert-MikrotikVLANHexCodes -Type VLANReceive -Hex $InputObject.vlni[$PortNumber])" 27 | VLANID = ConvertFrom-HexToInt -Hex $InputObject.dvid[$PortNumber] 28 | ForceVLANID = $ForceVLAN[$PortNumber] 29 | } 30 | [void]$Output.Add($PortOptions) 31 | $PortNumber += 1 32 | } 33 | Return $Output 34 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/Convert-MikrotikVLANConfig.ps1: -------------------------------------------------------------------------------- 1 | Function Convert-MikrotikVLANConfig 2 | { 3 | <# 4 | .Synopsis 5 | Converts the Mikrotik API VLANs page output from hex to boolean arrays/plain text 6 | #> 7 | 8 | param( 9 | [PSCustomObject]$InputObject, 10 | [Int]$TotalPorts 11 | ) 12 | 13 | [System.Collections.ArrayList]$Output = @() 14 | $VLAN_Instance = 0 15 | ForEach($VLANItem in $InputObject) 16 | { 17 | #[array]$EnabledPorts = ConvertFrom-HexToArray -Hex $InputObject.en 18 | $Object = [pscustomobject]@{ 19 | VLANID = [uint32]$InputObject.vid[$VLAN_Instance] 20 | PortIsolation = [uint32]$InputObject.piso[$VLAN_Instance] 21 | Learning = [uint32]$InputObject.lrn[$VLAN_Instance] 22 | Mirror = [uint32]$InputObject.mrr[$VLAN_Instance] 23 | IMGP_Snoop = [uint32]$InputObject.igmp[$VLAN_Instance] 24 | Members = ConvertFrom-HexToArray -Hex $InputObject.mbr[$VLAN_Instance] -ArrayLength $TotalPorts 25 | } 26 | [void]$Output.Add($Object) 27 | 28 | $VLAN_Instance += 1 29 | } 30 | Return $Output 31 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/Convert-MikrotikVLANHexCodes.ps1: -------------------------------------------------------------------------------- 1 | Function Convert-MikrotikVLANHexCodes 2 | { 3 | param( 4 | [ValidateSet('VLANMode','VLANReceive')] 5 | [Parameter(Mandatory=$true)] 6 | $Type, 7 | [Parameter(Mandatory=$true, ParameterSetName='Hex')] 8 | $Hex, 9 | [Parameter(Mandatory=$true, ParameterSetName='String')] 10 | [String]$String 11 | ) 12 | 13 | Switch($Type) 14 | { 15 | VLANMode 16 | { 17 | $Hashtable = @{ 18 | '0x00' = 'Disabled' 19 | '0x01' = 'Optional' 20 | '0x02' = 'Enabled' 21 | '0x03' = 'Strict' 22 | } 23 | } 24 | VLANReceive 25 | { 26 | $Hashtable = @{ 27 | '0x00' = 'Any' 28 | '0x01' = 'Only Tagged' 29 | '0x02' = 'Only Untagged' 30 | } 31 | } 32 | } 33 | ForEach($Code in $Hashtable.GetEnumerator()) 34 | { 35 | If($Hex -ne '') 36 | { 37 | If($Code.Key -eq $Hex) 38 | { 39 | Return $Code.Value 40 | } 41 | } 42 | If($String -ne '') 43 | { 44 | If($Code.Value -eq $String) 45 | { 46 | Return $Code.Key 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/ConvertFrom-ArrayToHex.ps1: -------------------------------------------------------------------------------- 1 | Function ConvertFrom-ArrayToHex 2 | { 3 | <# 4 | .Synopsis 5 | Converts a boolean array to hex 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | [Array]$Array 11 | ) 12 | 13 | [string]$BinaryString = '' 14 | [array]::Reverse($Array) 15 | ForEach($Item in $Array) 16 | { 17 | If($Item -eq $true) 18 | { 19 | $Binary = '1' 20 | } 21 | ElseIf($Item -eq $false) 22 | { 23 | $Binary = '0' 24 | } 25 | $BinaryString += $Binary 26 | } 27 | 28 | $Hex = ("0x$(([Convert]::ToUInt32($BinaryString, 2)).ToString('X').PadLeft(8,'0'))").ToLower() 29 | Return $Hex 30 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/ConvertFrom-HexToArray.ps1: -------------------------------------------------------------------------------- 1 | Function ConvertFrom-HexToArray 2 | { 3 | <# 4 | .Synopsis 5 | Converts a the Mikrotik hex to a boolean array 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | [String]$Hex, 11 | [Parameter(Mandatory=$true)] 12 | [int]$ArrayLength 13 | ) 14 | 15 | $Binary = ConvertFrom-HexToBinary -Hex $Hex -PadLength $ArrayLength 16 | $Output = @() 17 | [Array]$CharArray = ($Binary[-1..-$Binary.Length] -join '').ToCharArray() 18 | ForEach($Item in $CharArray) 19 | { 20 | $Result = $true 21 | If($Item -eq '0') 22 | { 23 | $Result = $false 24 | } 25 | [array]$Output += $Result 26 | } 27 | Return $Output 28 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/ConvertFrom-HexToBinary.ps1: -------------------------------------------------------------------------------- 1 | Function ConvertFrom-HexToBinary 2 | { 3 | <# 4 | .Synopsis 5 | Converts a hex to binary 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | $Hex, 11 | [Parameter(Mandatory=$true)] 12 | [int]$PadLength 13 | ) 14 | 15 | If($Hex -like "0x*") 16 | { 17 | $Hex = $Hex.Replace("0x",'') 18 | } 19 | 20 | [byte[]]$Bytes = ($Hex -split '(.{2})' -ne '' -replace '^', '0x') 21 | 22 | ForEach($Byte in $Bytes) 23 | { 24 | $Binary += "$([string]([Convert]::ToString($Byte, 2)).PadLeft(8,'0'))" 25 | } 26 | $Binary = $Binary.TrimStart('0') 27 | $Binary = $Binary.PadLeft($PadLength,'0') 28 | Return $Binary 29 | } 30 | -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/ConvertFrom-HexToInt.ps1: -------------------------------------------------------------------------------- 1 | Function ConvertFrom-HexToInt 2 | { 3 | <# 4 | .Synopsis 5 | Converts hex to an base10 integer 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | $Hex 11 | ) 12 | 13 | $Int = [uint32]$Hex 14 | Return $Int 15 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/ConvertFrom-HexToString.ps1: -------------------------------------------------------------------------------- 1 | Function ConvertFrom-HexToString 2 | { 3 | <# 4 | .Synopsis 5 | Converts hex to a string 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | $Hex 11 | ) 12 | 13 | If($Hex -like "0x*") 14 | { 15 | $Hex = $Hex.Replace("0x",'') 16 | } 17 | 18 | [string]$String = '' 19 | $Hex -split '(.{2})' -ne '' | ForEach-Object { 20 | $String += [char][byte]"0x$_" 21 | } 22 | 23 | Return $String 24 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/ConvertFrom-IntToHex.ps1: -------------------------------------------------------------------------------- 1 | Function ConvertFrom-IntToHex 2 | { 3 | <# 4 | .Synopsis 5 | Converts a integer to hex 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | [Int]$Int, 11 | [Parameter(Mandatory=$true)] 12 | [Int]$PadLength 13 | ) 14 | 15 | [string]$Hex = '{0:X}' -f $Int 16 | $Padded = $Hex.PadLeft($PadLength, '0') 17 | $Hex = "0x$Padded" 18 | Return $Hex 19 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/ConvertFrom-MikrotikToJson.ps1: -------------------------------------------------------------------------------- 1 | Function ConvertFrom-MikrotikToJson 2 | { 3 | <# 4 | .Synopsis 5 | Converts the non-standard JSON output from the Mikrotik API into parsable JSON to be imported into Powershell for later use 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | [string]$InputObject 11 | ) 12 | 13 | $JsonDump = $InputObject 14 | 15 | $WordRegex = '(\w+)' 16 | $SingleQuoteRegex = "(\')" 17 | $DoubleDoubleQuoteRegex = '\"{2}(\w+)\"{2}' 18 | 19 | $FixedJson = $JsonDump -replace $SingleQuoteRegex, '"' 20 | $FixedJson = $FixedJson -replace $WordRegex,'"$1"' 21 | $FixedJson = $FixedJson -replace $DoubleDoubleQuoteRegex, '"$1"' 22 | 23 | $FixedJson = $FixedJson -replace "],}","]}" 24 | If($FixedJson -like "*,") 25 | { 26 | } 27 | Try 28 | { 29 | $JsonObject = $FixedJson | ConvertFrom-Json 30 | } 31 | Catch 32 | { 33 | $FixedJson | Set-Clipboard 34 | Return "Failed JSON conversion sent to clipboard" 35 | } 36 | Return $JsonObject 37 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/private/ConvertFrom-StringToHex.ps1: -------------------------------------------------------------------------------- 1 | Function ConvertFrom-StringToHex 2 | { 3 | <# 4 | .Synopsis 5 | Converts a string to hex 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | [AllowEmptyString()] 11 | [string]$String 12 | ) 13 | 14 | $Hex = '' 15 | $CharArray = $String.ToCharArray() 16 | Foreach ($Char in $CharArray) 17 | { 18 | $Hex = $Hex + [System.String]::Format("{0:X2}", [System.Convert]::ToUInt32($Char)) 19 | } 20 | Return $Hex 21 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/public/Get-MikrotikLinks.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MikrotikLinks 2 | { 3 | <# 4 | .Synopsis 5 | Calls the Mikrotik SwitchOS API to retrieve the information about the switch ports (links page http:///index.html#link) 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | [PSCredential]$Credential, 11 | [Parameter(Mandatory=$false)] 12 | [URI]$URL, 13 | [Parameter(Mandatory=$false)] 14 | [ValidateSet('rj45','sfp')] 15 | [String]$Type 16 | ) 17 | 18 | #Runs main rest method 19 | $Response = Invoke-MikrotikRestMethod -Method Get -URI $URL -Query link.b -Credential $Credential 20 | 21 | #Retrieves the total amount of ports on the switch, helps with calculating the link parameters 22 | $TotalPorts = Get-MikrotikTotalPorts -Credential $Credential -URL $URL 23 | 24 | #Uses the JSON retrieved from $Response, and converts it from hex/binary to human readable information 25 | $Output = Convert-MikrotikLinks -InputObject $Response -TotalPorts $TotalPorts 26 | If($Type -ne '') 27 | { 28 | Return $Output | Where-Object PortType -eq $Type 29 | } 30 | Else 31 | { 32 | Return $Output 33 | } 34 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/public/Get-MikrotikPoE.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MikrotikPoE 2 | { 3 | param( 4 | [Parameter(Mandatory=$true)] 5 | [PSCredential]$Credential, 6 | [Parameter(Mandatory=$false)] 7 | [URI]$URL 8 | ) 9 | 10 | $Links = Get-MikrotikLinks -Credential $Credential -URL $URL 11 | 12 | $Response = Invoke-MikrotikRestMethod -Method Get -URI $URL -Credential $Credential -Query poe.b 13 | $TotalPorts = Get-MikrotikTotalPorts -Credential $Credential -URL $URL 14 | $Output = Convert-MikrotikPoE -InputObject $Response -Links $Links -TotalPorts $TotalPorts 15 | 16 | Return $Output 17 | } 18 | -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/public/Get-MikrotikSFP.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MikrotikSFP 2 | { 3 | <# 4 | .Synopsis 5 | Calls the Mikrotik SwitchOS API to retrieve the information about the switch SFP ports (links page http:///index.htmll#sfp) 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | [PSCredential]$Credential, 11 | [Parameter(Mandatory=$false)] 12 | [URI]$URL 13 | ) 14 | 15 | $Links = Get-MikrotikLinks -Credential $Credential -URL $URL -Type sfp 16 | 17 | $Response = Invoke-MikrotikRestMethod -Method Get -URI $URL -Query sfp.b -Credential $Credential 18 | $Output = Convert-MikrotikSFP -InputObject $Response -Links $Links 19 | Return $Output 20 | } 21 | -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/public/Get-MikrotikTotalPorts.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MikrotikTotalPorts 2 | { 3 | <# 4 | .Synopsis 5 | Returns the total number of ports 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | [PSCredential]$Credential, 11 | [Parameter(Mandatory=$false)] 12 | [URI]$URL 13 | ) 14 | 15 | $Response = Invoke-MikrotikRestMethod -Method Get -URI $URL -Query link.b -Credential $Credential 16 | $Output = [uint32]$Response.prt 17 | Return $Output 18 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/public/Get-MikrotikVLANConfig.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MikrotikVLANConfig 2 | { 3 | <# 4 | .Synopsis 5 | Calls the Mikrotik SwitchOS API to retrieve the information about the VLANs configuration (links page http:///index.html#vlans) 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | [PSCredential]$Credential, 11 | [Parameter(Mandatory=$false)] 12 | [URI]$URL 13 | ) 14 | 15 | $Response = Invoke-MikrotikRestMethod -Method Get -URI $URL -Query vlan.b -Credential $Credential 16 | 17 | $Output = Convert-MikrotikVLANConfig -InputObject $Response 18 | Return $Output 19 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/public/Get-MikrotikVLANs.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MikrotikVLANs 2 | { 3 | <# 4 | .Synopsis 5 | Calls the Mikrotik SwitchOS API to retrieve the information about the VLAN configuration (links page http:///index.html#vlan) 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$true)] 10 | [PSCredential]$Credential, 11 | [Parameter(Mandatory=$false)] 12 | [URI]$URL 13 | ) 14 | 15 | $Links = Get-MikrotikLinks -Credential $Credential -URL $URL 16 | 17 | $Response = Invoke-MikrotikRestMethod -Method Get -URI $URL -Query fwd.b -Credential $Credential 18 | $TotalPorts = Get-MikrotikTotalPorts -Credential $Credential -URL $URL 19 | $Output = Convert-MikrotikVLAN -InputObject $Response -Links $Links -TotalPorts $TotalPorts 20 | Return $Output 21 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/public/Invoke-MikrotikRestMethod.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-MikrotikRestMethod 2 | { 3 | <# 4 | .Synopsis 5 | Sends a Rest Method request to the Mikrotik SwitchOS API 6 | #> 7 | 8 | param( 9 | [Parameter(Mandatory=$True)] 10 | [Microsoft.PowerShell.Commands.WebRequestMethod]$Method, 11 | [Parameter(Mandatory=$True)] 12 | [URI]$URI, 13 | [Parameter(Mandatory=$True)] 14 | [String]$Query, 15 | [Parameter(Mandatory=$true)] 16 | [PSCredential]$Credential, 17 | [Parameter(Mandatory=$False)] 18 | [String]$Body, 19 | [Parameter(Mandatory=$false)] 20 | [Switch]$NoConversion 21 | ) 22 | 23 | Begin 24 | { 25 | $NetAssembly = [Reflection.Assembly]::GetAssembly([System.Net.Configuration.SettingsSection]) 26 | If($NetAssembly) 27 | { 28 | $BindingFlags = [Reflection.BindingFlags] "Static,GetProperty,NonPublic" 29 | $SettingsType = $netAssembly.GetType("System.Net.Configuration.SettingsSectionInternal") 30 | 31 | $Instance = $SettingsType.InvokeMember("Section", $bindingFlags, $null, $null, @()) 32 | If($Instance) 33 | { 34 | $BindingFlags = "NonPublic","Instance" 35 | $UseUnsafeHeaderParsingField = $SettingsType.GetField("useUnsafeHeaderParsing", $bindingFlags) 36 | If($UseUnsafeHeaderParsingField) 37 | { 38 | $UseUnsafeHeaderParsingField.SetValue($instance, $true) 39 | } 40 | } 41 | } 42 | } 43 | 44 | Process 45 | { 46 | 47 | [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} 48 | 49 | $Headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" 50 | $Headers.Add("Accept", "*/*") 51 | $Headers.Add("Accept-Language", "en-US,en;q=0.5") 52 | $Headers.Add("Accept-Encoding", "gzip, deflate") 53 | $Headers.Add("Content-Type", "text/plain") 54 | $Headers.Add("Origin", "$URI") 55 | $Headers.Add("Referer", "$URI/index.html") 56 | 57 | $URI = "$URI" + $Query 58 | 59 | $InvokeParams = @{ 60 | Uri = $URI 61 | Method = $Method 62 | Credential = $Credential 63 | Headers = $Headers 64 | } 65 | 66 | If($Method -eq 'POST') 67 | { 68 | If($Body -eq '') 69 | { 70 | Write-Error "Unable to send POST request with no body" 71 | Break 72 | } 73 | [void]$InvokeParams.Add('Body',$Body) 74 | } 75 | 76 | $Response = (Invoke-WebRequest @InvokeParams -ErrorAction SilentlyContinue).Content 77 | } 78 | End 79 | { 80 | #Allows for troubleshooting, it will spit out the plaintext response for the API, instead of the response converted to proper JSON 81 | If($NoConversion -eq $true) 82 | { 83 | $InitalObject = $Response 84 | } 85 | Else 86 | { 87 | $InitalObject = ConvertFrom-MikrotikToJson -InputObject $Response 88 | } 89 | Return $InitalObject 90 | } 91 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/public/Set-MikrotikSwitchPort.ps1: -------------------------------------------------------------------------------- 1 | Function Set-MikrotikSwitchPort 2 | { 3 | <# 4 | .Synopsis 5 | Allows for changes to be made to a switch port via the Mikrotik SwitchOS API 6 | .Example 7 | Set-MikrotikSwitchPort -PortNumber 4 -PortName "NewPortName" -Enabled $true -Credential (Get-Credential) -Url http:// 8 | #> 9 | 10 | param( 11 | [Parameter(Mandatory=$true)] 12 | [Int]$PortNumber, 13 | [Parameter(Mandatory=$false)] 14 | [String]$PortName, 15 | [Parameter(Mandatory=$false)] 16 | [Boolean]$Enabled = $true, 17 | [Parameter(Mandatory=$false)] 18 | [Boolean]$AutoNeg = $true, 19 | [Parameter(Mandatory=$true)] 20 | [PSCredential]$Credential, 21 | [Parameter(Mandatory=$false)] 22 | [URI]$URL, 23 | [Parameter(Mandatory=$false)] 24 | [Switch]$Force 25 | ) 26 | 27 | $HardConfirm = $false 28 | $NewConfig = '' 29 | #Retrieves the current config for the switch 30 | $MikrotikConfig = Invoke-MikrotikRestMethod -Method Get -URI $URL -Query link.b -Credential $Credential 31 | 32 | #Retrieves the current links 33 | $CurrentLinks = Get-MikrotikLinks -Credential $Credential -URL $URL 34 | 35 | $PortNameArray = $CurrentLinks | Select-Object -ExpandProperty PortName 36 | $PortEnabled = $CurrentLinks | Select-Object -ExpandProperty Enabled 37 | $PortAutoNeg = $CurrentLinks | Select-Object -ExpandProperty AutoNeg 38 | 39 | If($PortName -ne '') 40 | { 41 | $NewPortName = $PortName 42 | 43 | If($PortNameArray[$PortNumber - 1] -ne $NewPortName) 44 | { 45 | #Sets a new port name if the selected port (via -PortNumber) doesnt match the specified port name (-PortName) 46 | [string]$NewHexPortNameString = (ConvertFrom-StringToHex -String $NewPortName).ToLower() 47 | $MikrotikConfig.nm[$PortNumber - 1] = $NewHexPortNameString 48 | 49 | $HardConfirm = $true 50 | } 51 | } 52 | 53 | If($PortEnabled[$PortNumber - 1] -ne $Enabled) 54 | { 55 | $NewEnabledArray = $PortEnabled 56 | $NewEnabledArray[$PortNumber - 1] = $Enabled 57 | 58 | #Sets the port enabled state to -Enabled 59 | $NewEnabledHex = ConvertFrom-ArrayToHex -Array $NewEnabledArray 60 | $MikrotikConfig.en = $NewEnabledHex 61 | 62 | If($Enabled -eq $false) 63 | { 64 | $HardConfirm = $true 65 | } 66 | } 67 | 68 | If($PortAutoNeg[$PortNumber - 1] -ne $AutoNeg) 69 | { 70 | $NewAutoNegArray = $PortAutoNeg 71 | $NewAutoNegArray[$PortNumber - 1] = $AutoNeg 72 | 73 | #Sets the port auto-negotiation state to -AutoNeg 74 | $NewAutoNegHex = ConvertFrom-ArrayToHex -Array $NewAutoNegArray 75 | $MikrotikConfig.an = $NewAutoNegHex 76 | 77 | If($AutoNeg -eq $false) 78 | { 79 | $HardConfirm = $true 80 | } 81 | } 82 | 83 | #region Construct the new config to send to the switch 84 | $NameCount = 0 85 | $SpeedCount = 0 86 | 87 | $NewConfig = "{en:$($MikrotikConfig.en),nm:[" 88 | ForEach($PortNameHex in $MikrotikConfig.nm) 89 | { 90 | If($NameCount -lt ($MikrotikConfig.nm.count - 1)) 91 | { 92 | $NewConfig += "'$PortNameHex'," 93 | $NameCount += 1 94 | } 95 | Else 96 | { 97 | $NewConfig += "'$PortNameHex'" 98 | } 99 | } 100 | $NewConfig += "],an:$($MikrotikConfig.an),spdc:[" 101 | ForEach($SpeedConfig in $MikrotikConfig.spdc) 102 | { 103 | If($SpeedCount -lt ($MikrotikConfig.spdc.count - 1)) 104 | { 105 | $NewConfig += "'$SpeedConfig'," 106 | $SpeedCount += 1 107 | } 108 | Else 109 | { 110 | $NewConfig += "'$SpeedConfig'" 111 | } 112 | } 113 | $NewConfig += "],dpxc:$($MikrotikConfig.dpxc),fctc:$($MikrotikConfig.fctc),fctr:$($MikrotikConfig.fctr)}" 114 | #endregion 115 | 116 | <# 117 | Added this here as there is a chance that if the incorrect information is sent to the switch, it can corrupt the config and the switch has to be hard reset. 118 | From a fair bit of testing, most of the kinks have been ironed out, but rather safe than sorry 119 | #> 120 | If(($HardConfirm -eq $true) -and ($Force -ne $true)) 121 | { 122 | $ConsoleWidth = $Host.UI.RawUI.BufferSize.Width 123 | $Exclaimation = '!' * $ConsoleWidth 124 | Write-Host "`n`rConfig that is going to be sent is" -ForegroundColor Yellow 125 | Write-Host $Exclaimation -ForegroundColor Yellow 126 | Write-Host "$NewConfig`n`r" -ForegroundColor White 127 | Write-Host "$Exclaimation`n`r" -ForegroundColor Yellow 128 | 129 | $HardConfirmContinue = Read-Host -Prompt 'Send New Config? Y/N' 130 | 131 | If($HardConfirmContinue -ne 'Y') 132 | { 133 | Write-Host "Breaking Out..." 134 | Break 135 | } 136 | ElseIf($HardConfirmContinue -eq 'Y') 137 | { 138 | Invoke-MikrotikRestMethod -Method Post -URI $URL -Credential $Credential -Query link.b -Body $NewConfig -NoConversion 139 | } 140 | } 141 | Else 142 | { 143 | Invoke-MikrotikRestMethod -Method Post -URI $URL -Credential $Credential -Query link.b -Body $NewConfig -NoConversion 144 | } 145 | } -------------------------------------------------------------------------------- /powershell/MikrotikPSwitchOS/public/Set-MikrotikVLAN.ps1: -------------------------------------------------------------------------------- 1 | Function Set-MikrotikVLAN 2 | { 3 | <# 4 | .Synopsis 5 | Allows for changes to be made to a VLAN configuration via the Mikrotik SwitchOS API 6 | .Example 7 | Set-MikrotikVLAN-PortNumber 4 -VLANMode "Enabled" -VLANReceive "Only Untagged" -Credential (Get-Credential) -Url http:// 8 | #> 9 | 10 | param( 11 | [Parameter(Mandatory=$true)] 12 | [Int]$PortNumber, 13 | [Parameter(Mandatory=$false)] 14 | [ValidateSet('Disabled','Optional','Enabled','Strict')] 15 | [string]$VLANMode, 16 | [Parameter(Mandatory=$false)] 17 | [ValidateSet('Any','Only Tagged','Only Untagged')] 18 | [string]$VLANReceive, 19 | [Parameter(Mandatory=$false)] 20 | [Int]$VLANID, 21 | [Parameter(Mandatory=$true)] 22 | [PSCredential]$Credential, 23 | [Parameter(Mandatory=$false)] 24 | [URI]$URL, 25 | [Parameter(Mandatory=$false)] 26 | [Switch]$Force 27 | ) 28 | 29 | $HardConfirm = $false 30 | $NewConfig = '' 31 | #Retrieves the current config for the switch 32 | $MikrotikConfig = Invoke-MikrotikRestMethod -Method Get -URI $URL -Query fwd.b -Credential $Credential 33 | 34 | #Retrieves the current VLANs 35 | $CurrentVLANs = Get-MikrotikVLANs -Credential $Credential -URL $URL 36 | 37 | $VLANModeArray = $CurrentVLANs | Select-Object -ExpandProperty VLANMode 38 | $VLANReceiveArray = $CurrentVLANs | Select-Object -ExpandProperty VLANReceive 39 | $DefaultVLANArray = $CurrentVLANs | Select-Object -ExpandProperty VLANID 40 | 41 | If($VLANMode -ne '') 42 | { 43 | If($VLANModeArray[$PortNumber - 1] -ne $VLANMode) 44 | { 45 | #Sets a new VLAN mode if the selected port (via -PortNumber) doesnt match the specified VLAN mode (-VLANMode) 46 | $NewVLANMode = Convert-MikrotikVLANHexCodes -Type VLANMode -String $VLANMode 47 | $MikrotikConfig.vlan[$PortNumber - 1] = $NewVLANMode 48 | 49 | $HardConfirm = $true 50 | } 51 | } 52 | If($VLANReceive -ne '') 53 | { 54 | If($VLANReceiveArray[$PortNumber - 1] -ne $VLANReceive) 55 | { 56 | #Sets a new VLAN receive mode if the selected port (via -PortNumber) doesnt match the specified VLAN receive mode (-VLANReceive) 57 | $NewVLANReceive = Convert-MikrotikVLANReceive -String $VLANReceive 58 | $MikrotikConfig.vlni[$PortNumber - 1] = $NewVLANReceive 59 | 60 | $HardConfirm = $true 61 | } 62 | } 63 | If($VLANID -ne $null) 64 | { 65 | If($DefaultVLANArray[$PortNumber - 1] -ne $VLANID ) 66 | { 67 | #Sets a new VLAN ID if the selected port (via -PortNumber) doesnt match the specified VLAN ID (-VLANID) 68 | $NewDefaultVLAN = ConvertFrom-IntToHex -Int $VLANID -PadLength 4 69 | $MikrotikConfig.dvid[$PortNumber - 1] = $NewDefaultVLAN 70 | 71 | $HardConfirm = $true 72 | } 73 | } 74 | 75 | $VLANModeCount = 0 76 | $VLANReceiveCount = 0 77 | $VLANIDCount = 0 78 | 79 | #region Construct the new config to send to the switch 80 | $NewConfig = "{vlan:[" 81 | ForEach($PortVLANMode in $MikrotikConfig.vlan) 82 | { 83 | If($VLANModeCount -lt ($MikrotikConfig.vlan.count - 1)) 84 | { 85 | $NewConfig += "$PortVLANMode," 86 | $VLANModeCount += 1 87 | } 88 | Else 89 | { 90 | $NewConfig += "$PortVLANMode" 91 | } 92 | } 93 | $NewConfig += "],vlni:[" 94 | ForEach($PortVLANReceive in $MikrotikConfig.vlni) 95 | { 96 | If($VLANReceiveCount -lt ($MikrotikConfig.vlni.count - 1)) 97 | { 98 | $NewConfig += "$PortVLANReceive," 99 | $VLANReceiveCount += 1 100 | } 101 | Else 102 | { 103 | $NewConfig += "$PortVLANReceive" 104 | } 105 | 106 | } 107 | $NewConfig += "],dvid:[" 108 | ForEach($PortVLANDefault in $MikrotikConfig.dvid) 109 | { 110 | If($VLANIDCount -lt ($MikrotikConfig.dvid.count - 1)) 111 | { 112 | $NewConfig += "$PortVLANDefault," 113 | $VLANIDCount += 1 114 | } 115 | Else 116 | { 117 | $NewConfig += "$PortVLANDefault" 118 | } 119 | 120 | } 121 | $NewConfig += "]}" 122 | #endregion 123 | 124 | <# 125 | Added this here as there is a chance that if the incorrect information is sent to the switch, it can corrupt the config and the switch has to be hard reset. 126 | From a fair bit of testing, most of the kinks have been ironed out, but rather safe than sorry 127 | #> 128 | If(($HardConfirm -eq $true) -and ($Force -ne $true)) 129 | { 130 | $ConsoleWidth = $Host.UI.RawUI.BufferSize.Width 131 | $Exclaimation = '!' * $ConsoleWidth 132 | Write-Host "`n`rConfig that is going to be sent is" -ForegroundColor Yellow 133 | Write-Host $Exclaimation -ForegroundColor Yellow 134 | Write-Host "$NewConfig`n`r" -ForegroundColor White 135 | Write-Host "$Exclaimation`n`r" -ForegroundColor Yellow 136 | 137 | $HardConfirmContinue = Read-Host -Prompt 'Send New Config? Y/N' 138 | 139 | If($HardConfirmContinue -ne 'Y') 140 | { 141 | Write-Host "Breaking Out..." 142 | Break 143 | } 144 | ElseIf($HardConfirmContinue -eq 'Y') 145 | { 146 | Invoke-MikrotikRestMethod -Method Post -URI $URL -Credential $Credential -Query fwd.b -Body $NewConfig -NoConversion 147 | } 148 | } 149 | Else 150 | { 151 | Invoke-MikrotikRestMethod -Method Post -URI $URL -Credential $Credential -Query fwd.b -Body $NewConfig -NoConversion 152 | } 153 | } -------------------------------------------------------------------------------- /python/mikrotik_switch_api.py: -------------------------------------------------------------------------------- 1 | import re 2 | import json 3 | import requests 4 | from requests.auth import HTTPDigestAuth 5 | 6 | def send_Mikrotik_Rest_Method(url, method, query, username, password, body=None): 7 | headers = { 8 | "Accept": "*/*", 9 | "Accept-Language": "en-US,en;q=0.5", 10 | "Accept-Encoding": "gzip, deflate", 11 | "Content-Type": "text/plain", 12 | "Origin": f"{url}", 13 | "Referer": f"{url}/index.html" 14 | } 15 | 16 | url = f"{url}/{query}" 17 | 18 | request_params = dict( 19 | method = method, 20 | url = url, 21 | headers = headers, 22 | auth = HTTPDigestAuth(username=username, password=password) 23 | ) 24 | 25 | if body != None: 26 | request_params['data'] = body 27 | 28 | response = requests.request(**request_params) 29 | return response.text 30 | 31 | def convert_Mikrotik_Json(input_object): 32 | json_dump = input_object 33 | 34 | word_regex = r"(\w+)" 35 | single_quote_regex = r"(\')" 36 | double_double_quote_regex = r'\"{2}(\w+)\"{2}' 37 | 38 | json_dump = re.sub(word_regex, r'"\1"', json_dump) 39 | json_dump = re.sub(single_quote_regex, r'"', json_dump) 40 | json_dump = re.sub(double_double_quote_regex, r'"\1"', json_dump) 41 | json_dump = re.sub('],}','}]', json_dump) 42 | 43 | json_output = json.loads(json_dump) 44 | 45 | return json_output 46 | 47 | def get_Mikrotik_Hosts(url, username, password): 48 | query = '!dhost.b' 49 | method = 'GET' 50 | response = send_Mikrotik_Rest_Method(url=url, query=query, method=method, username=username, password=password) 51 | hosts = convert_Mikrotik_Json(input_object=response) 52 | links = get_Mikrotik_Links(url=url, username=username, password=password) 53 | 54 | output = [] 55 | for host in hosts: 56 | mac_address = re.sub(r'(.{2})(?!$)', r'\1:', host['adr']) 57 | vlan_id = int(host['vid'], 16) 58 | port_number = int(host['prt'], 16) + 1 59 | port_name = links[port_number - 1]['port_name'] 60 | 61 | object = { 62 | 'mac_address':mac_address, 63 | 'vlan_id':vlan_id, 64 | 'port_name':port_name, 65 | 'port_number':port_number 66 | } 67 | output.append(object) 68 | 69 | return output 70 | 71 | def convert_Mikrotik_Link_Speed(hex_string): 72 | SwOS_link_speeds = { 73 | '0x01': 0.1, 74 | '0x02': 1.0, 75 | '0x07': 0.0, 76 | '0x04': 0.0, 77 | '0x03': 10.0 78 | } 79 | 80 | for speeds in SwOS_link_speeds: 81 | if speeds == hex_string: 82 | return SwOS_link_speeds[speeds] 83 | 84 | def convert_Mikrotik_Hex_Array(hex_string, pad_length): 85 | output = [] 86 | binary = f'{int(hex_string, 16):0>{pad_length}b}' 87 | for element in binary: 88 | if element == '1': 89 | output.append(True) 90 | else: 91 | output.append(False) 92 | output.reverse() 93 | return output 94 | 95 | def convert_Mikrotik_Array_Hex(array, padding=8): 96 | binary_string = str('') 97 | array.reverse() 98 | for item in array: 99 | if item == True: 100 | bin = '1' 101 | elif item == False: 102 | bin = '0' 103 | binary_string += bin 104 | 105 | padding = padding + 2 106 | hex_output = f"{int(binary_string, 2):#0{padding}x}" 107 | return hex_output 108 | 109 | def convert_Mikrotik_Vlan_Mode(hex_string=None, string=None): 110 | vlan_modes = { 111 | '0x00': 'Disabled', 112 | '0x01': 'Optional', 113 | '0x02': 'Enabled', 114 | '0x03': 'Strict' 115 | } 116 | 117 | for key, value in vlan_modes.items(): 118 | if hex_string != None and key == hex_string: 119 | return value 120 | if string != None and value == string: 121 | return key 122 | 123 | def convert_Mikrotik_Vlan_Receive(hex_string=None, string=None): 124 | vlan_receive = { 125 | '0x00': 'Any', 126 | '0x01': 'Only Tagged', 127 | '0x02': 'Only Untagged' 128 | } 129 | 130 | for key, value in vlan_receive.items(): 131 | if hex_string != None and key == hex_string: 132 | return value 133 | if string != None and value == string: 134 | return key 135 | 136 | def get_Mikrotik_Links(url, username, password, port_number=None, port_name=None, output_only=None): 137 | query = 'link.b' 138 | method = 'GET' 139 | response = send_Mikrotik_Rest_Method(url=url, query=query, method=method, username=username, password=password) 140 | links = convert_Mikrotik_Json(input_object=response) 141 | 142 | total_ports = int(links['prt'], 16) 143 | port_instance = 0 144 | output = [] 145 | 146 | enabled_ports = convert_Mikrotik_Hex_Array(hex_string=links['en'], pad_length=total_ports) 147 | link_active = convert_Mikrotik_Hex_Array(hex_string=links['lnk'] , pad_length=total_ports) 148 | auto_neg_ports = convert_Mikrotik_Hex_Array(hex_string=links['an'], pad_length=total_ports) 149 | duplex_ports = convert_Mikrotik_Hex_Array(hex_string=links['dpx'], pad_length=total_ports) 150 | 151 | while port_instance < total_ports: 152 | object = { 153 | 'enabled': enabled_ports[port_instance], 154 | 'port_number': port_instance + 1, 155 | 'port_name': bytes.fromhex(links['nm'][port_instance]).decode('utf-8'), 156 | 'link_speed': convert_Mikrotik_Link_Speed(hex_string=links['spd'][port_instance]), 157 | 'link_active': link_active[port_instance], 158 | 'auto_neg': auto_neg_ports[port_instance], 159 | 'full_duplex': duplex_ports[port_instance], 160 | } 161 | port_instance += 1 162 | output.append(object) 163 | 164 | output_options = ( 165 | 'port_name', 166 | 'enabled', 167 | 'auto_neg' 168 | ) 169 | 170 | result = [] 171 | if output_only in output_options: 172 | for item in output: 173 | result.append(item[output_only]) 174 | else: 175 | if port_number != None: 176 | result = output[port_number - 1] 177 | elif port_name != None: 178 | for ports in output: 179 | if ports['port_name'] == port_name: 180 | result.append(ports) 181 | else: 182 | result = output 183 | 184 | return result 185 | 186 | def get_Mikrotik_Vlan(url, username, password, port_number=None, port_name=None, vlan_id=None, output_only=None): 187 | query = 'fwd.b' 188 | method = 'GET' 189 | response = send_Mikrotik_Rest_Method(url=url, query=query, method=method, username=username, password=password) 190 | links = get_Mikrotik_Links(url=url, username=username, password=password) 191 | vlans = convert_Mikrotik_Json(input_object=response) 192 | 193 | total_ports = len(links) 194 | port_instance = 0 195 | output = [] 196 | 197 | force_vlan = convert_Mikrotik_Hex_Array(hex_string=vlans['fvid'], pad_length=total_ports) 198 | 199 | while port_instance < total_ports: 200 | object = { 201 | 'port_number': port_instance + 1, 202 | 'port_name': links[port_instance]['port_name'], 203 | 'vlan_mode': convert_Mikrotik_Vlan_Mode(hex_string=vlans['vlan'][port_instance]), 204 | 'vlan_receive': convert_Mikrotik_Vlan_Receive(hex_string=vlans['vlni'][port_instance]), 205 | 'vlan_id': int(vlans['dvid'][port_instance], 16), 206 | 'force_vlan': force_vlan[port_instance], 207 | } 208 | port_instance += 1 209 | output.append(object) 210 | 211 | output_options = ( 212 | 'vlan_mode', 213 | 'vlan_receive', 214 | 'vlan_id' 215 | ) 216 | 217 | result = [] 218 | if output_only in output_options: 219 | for item in output: 220 | result.append(item[output_only]) 221 | else: 222 | if port_number != None: 223 | result = output[port_number - 1] 224 | elif port_name != None: 225 | for ports in output: 226 | if ports['port_name'] == port_name: 227 | result.append(ports) 228 | elif vlan_id != None: 229 | for ports in output: 230 | if ports['vlan_id'] == vlan_id: 231 | result.append(ports) 232 | else: 233 | result = output 234 | 235 | return result 236 | 237 | def get_Mikrotik_Vlan_Config(url, username, password): 238 | query = 'vlan.b' 239 | method = 'GET' 240 | response = send_Mikrotik_Rest_Method(url=url, query=query, method=method, username=username, password=password) 241 | vlans = convert_Mikrotik_Json(input_object=response) 242 | 243 | vlan_instance = 0 244 | output = [] 245 | 246 | for vlan in vlans: 247 | object = { 248 | "vlan_id": int(vlans[vlan_instance]['vid'], 16), 249 | 'port_isolation': int(vlans[vlan_instance]['piso'], 16), 250 | 'learning': int(vlans[vlan_instance]['lrn'], 16), 251 | 'mirror': int(vlans[vlan_instance]['mrr'], 16), 252 | 'igmp_snoop': int(vlans[vlan_instance]['igmp'], 16), 253 | 'members': convert_Mikrotik_Hex_Array(hex_string=vlans[vlan_instance]['mbr'], pad_length=26) 254 | } 255 | vlan_instance += 1 256 | output.append(object) 257 | 258 | return output 259 | 260 | def set_Mikrotik_Switch_Port(url, username, password, port_number, port_name=None, enabled=True, auto_neg=True): 261 | query = 'link.b' 262 | response = send_Mikrotik_Rest_Method(url=url, query=query, method='GET', username=username, password=password) 263 | mikrotik_config = convert_Mikrotik_Json(input_object=response) 264 | 265 | new_mikrotik_config = '' 266 | name_count = 1 267 | speed_count = 1 268 | 269 | get_Mikrotik_Link_params = dict( 270 | url = url, 271 | username = username, 272 | password = password 273 | ) 274 | 275 | port_names = get_Mikrotik_Links(**get_Mikrotik_Link_params, output_only='port_name') 276 | port_enabled = get_Mikrotik_Links(**get_Mikrotik_Link_params, output_only='enabled') 277 | port_auto_neg = get_Mikrotik_Links(**get_Mikrotik_Link_params, output_only='auto_neg') 278 | 279 | array_port_number = port_number - 1 280 | #print(mikrotik_config) 281 | if port_name != None: 282 | new_port_name = port_name 283 | if new_port_name not in port_names: 284 | new_port_name_hex = new_port_name.encode('utf-8').hex() 285 | mikrotik_config['nm'][array_port_number] = new_port_name_hex 286 | 287 | if port_enabled[array_port_number] != enabled: 288 | new_port_enabled = list(port_enabled) 289 | new_port_enabled[array_port_number] = enabled 290 | 291 | new_port_enabled_hex = convert_Mikrotik_Array_Hex(array=new_port_enabled) 292 | mikrotik_config['en'] = new_port_enabled_hex 293 | 294 | if port_auto_neg[array_port_number] != auto_neg: 295 | new_port_auto_neg = list(port_auto_neg) 296 | new_port_auto_neg[array_port_number] = auto_neg 297 | 298 | new_port_auto_neg_hex = convert_Mikrotik_Array_Hex(array=new_port_auto_neg) 299 | mikrotik_config['an'] = new_port_auto_neg_hex 300 | 301 | new_mikrotik_config += f"{{en:{mikrotik_config['en']},nm:[" 302 | for name_hex in mikrotik_config['nm']: 303 | if name_count <= (len(mikrotik_config['nm']) - 1): 304 | new_mikrotik_config += f"'{name_hex}'," 305 | name_count += 1 306 | else: 307 | new_mikrotik_config += f"'{name_hex}'" 308 | new_mikrotik_config += f"],an:{mikrotik_config['an']},spdc:[" 309 | for speed_hex in mikrotik_config['spdc']: 310 | if speed_count <= (len(mikrotik_config['spdc']) - 1): 311 | new_mikrotik_config += f"'{speed_hex}'," 312 | speed_count += 1 313 | else: 314 | new_mikrotik_config += f"'{speed_hex}'" 315 | new_mikrotik_config += f"],dpxc:{mikrotik_config['dpxc']},fctc:{mikrotik_config['fctc']},fctr:{mikrotik_config['fctr']}}}" 316 | 317 | send_Mikrotik_Rest_Method(url=url, query=query, method='POST', username=username, password=password, body=new_mikrotik_config) 318 | 319 | def set_Mikrotik_Vlan(url, username, password, port_number, vlan_mode=None, vlan_receive=None, vlan_id=None): 320 | query = 'fwd.b' 321 | response = send_Mikrotik_Rest_Method(url=url, query=query, method='GET', username=username, password=password) 322 | mikrotik_config = convert_Mikrotik_Json(input_object=response) 323 | 324 | get_Mikrotik_Vlan_params = dict( 325 | url = url, 326 | username = username, 327 | password = password 328 | ) 329 | 330 | array_port_number = port_number - 1 331 | 332 | vlan_mode_count = 1 333 | vlan_receive_count = 1 334 | vlan_id_count = 1 335 | 336 | vlan_mode_data = get_Mikrotik_Vlan(**get_Mikrotik_Vlan_params, output_only='vlan_mode')[array_port_number] 337 | vlan_receive_data = get_Mikrotik_Vlan(**get_Mikrotik_Vlan_params, output_only='vlan_receive')[array_port_number] 338 | vlan_id_data = get_Mikrotik_Vlan(**get_Mikrotik_Vlan_params, output_only='vlan_id')[array_port_number] 339 | 340 | if vlan_mode != None: 341 | if vlan_mode_data != vlan_mode: 342 | new_vlan_mode = convert_Mikrotik_Vlan_Mode(string=vlan_mode) 343 | 344 | mikrotik_config['vlan'][array_port_number] = new_vlan_mode 345 | print(new_vlan_mode) 346 | 347 | if vlan_receive != None: 348 | if vlan_receive_data != vlan_receive: 349 | new_vlan_receive = convert_Mikrotik_Vlan_Receive(string=vlan_receive) 350 | mikrotik_config['vlni'][array_port_number] = new_vlan_receive 351 | print(new_vlan_receive) 352 | 353 | if vlan_id != None: 354 | if vlan_id_data != vlan_id: 355 | padding = 6 356 | new_vlan_id = f"{vlan_id:#0{padding}x}" 357 | mikrotik_config['dvid'][array_port_number] = new_vlan_id 358 | print(new_vlan_id) 359 | 360 | new_mikrotik_config = '{vlan:[' 361 | for vlan_mode_hex in mikrotik_config['vlan']: 362 | if vlan_mode_count <= (len(mikrotik_config['vlan']) - 1): 363 | new_mikrotik_config += f"{vlan_mode_hex}," 364 | vlan_mode_count += 1 365 | else: 366 | new_mikrotik_config += f"{vlan_mode_hex}" 367 | 368 | new_mikrotik_config += '],vlni:[' 369 | for vlan_receive_hex in mikrotik_config['vlni']: 370 | if vlan_receive_count <= (len(mikrotik_config['vlni']) - 1): 371 | new_mikrotik_config += f"{vlan_receive_hex}," 372 | vlan_receive_count += 1 373 | else: 374 | new_mikrotik_config += f"{vlan_receive_hex}" 375 | 376 | new_mikrotik_config += '],dvid:[' 377 | for vlan_id_hex in mikrotik_config['dvid']: 378 | if vlan_id_count <= (len(mikrotik_config['dvid']) - 1): 379 | new_mikrotik_config += f"{vlan_id_hex}," 380 | vlan_id_count += 1 381 | else: 382 | new_mikrotik_config += f"{vlan_id_hex}" 383 | 384 | new_mikrotik_config += ']}' 385 | 386 | send_Mikrotik_Rest_Method(url=url, query=query, method='POST', username=username, password=password, body=new_mikrotik_config) --------------------------------------------------------------------------------