├── APIv2 └── README.md ├── GetCDPFromAPI ├── GetCustomerListwithSites-Prompted.ps1 ├── GetDeviceInfor-Prompted.ps1 ├── GetFilteredDevicesPrinterInfo-Prompted.ps1 └── README.md /APIv2/README.md: -------------------------------------------------------------------------------- 1 | # How To: N-Central API Automation 2 | 3 | ## Table of Content 4 | 5 | - [How To: N-Central API Automation](#how-to--n-central-api-automation) 6 | * [Table of Content](#table-of-content) 7 | - [Overview](#overview) 8 | - [Connecting](#connecting) 9 | * [PS-NCentral](#ps-ncentral) 10 | + [Multiple PS-NCentral server connections](#multiple-ps-ncentral-server-connections) 11 | * [PowerShell WebserviceProxy](#powershell-webserviceproxy) 12 | - [Performing Queries](#performing-queries) 13 | * [PS-NCentral](#ps-ncentral-1) 14 | + [Advanced PS-NCentral querying](#advanced-ps-ncentral-querying) 15 | * [PowerShell WebserviceProxy](#powershell-webserviceproxy-1) 16 | + [Bind to the namespace, using the Webserviceproxy](#bind-to-the-namespace--using-the-webserviceproxy) 17 | - [Updating a Value](#updating-a-value) 18 | * [PS-NCentral](#ps-ncentral-2) 19 | + [Updating with pipelining](#updating-with-pipelining) 20 | + [Updating Custom Device Properties](#updating-custom-device-properties) 21 | + [Custom Property options](#custom-property-options) 22 | - [Encoding](#encoding) 23 | - [Comma-Separated Values](#comma-separated-values) 24 | - [Format-properties](#format-properties) 25 | * [PowerShell WebserviceProxy](#powershell-webserviceproxy-2) 26 | + [Registration token injection](#registration-token-injection) 27 | + [Gather organization property ID](#gather-organization-property-id) 28 | + [Update customer property](#update-customer-property) 29 | + [Add new a new Customer](#add-new-a-new-customer) 30 | - [Appendix A – N-Central Web Service members](#appendix-a---n-central-web-service-members) 31 | - [Appendix B - PS-NCentral cmdlets](#appendix-b---ps-ncentral-cmdlets) 32 | - [Appendix C – GetAllCustomerProperties.ps1](#appendix-c---getallcustomerpropertiesps1) 33 | - [Appendix D – Customer Property variables](#appendix-d---customer-property-variables) 34 | - [Appendix E - All PS-Central Methods](#appendix-e---all-ps-central-methods) 35 | - [Appendix F - Common Error Codes](#appendix-f---common-error-codes) 36 | - [Appendix G - Issue Status](#appendix-g---issue-status) 37 | - [Appendix H - WebserviceProxy Alternative](#appendix-h---webserviceproxy-alternative) 38 | - [Credits](#credits) 39 | 40 | Table of contents generated with markdown-toc 41 | 42 | 43 | # Overview 44 | 45 | N-Central's API is a flexible, programmatic, object oriented, Java based interface by which developers can achieve integration and automation via native SOAP API calls. 46 | 47 | For the purposes of this guide we'll be covering connectivity and basic usage with PowerShell based automation through the PS-NCentral module, as well as native WebserviceProxy cmdlet. 48 | 49 | The information covering the PS-NCentral is useful for those with starting some experience with PowerShell or need to quickly put together code where module dependency isn't an issue, while the usage of the WebserviceProxy method is for those more familiar with object oriented coding or need code portatability. As of version 1.2 PS-NCentral uses PowerShell 7 for cross compatability to be able to run Windows/Linux or in an Azure function. 50 | 51 | PS-NCentral provides cmdlets for 17 Get cmdlets and 4 Set cmdlets (See Appendix B) that cover the majority, so should cover the majority of automation. This can be downloaded from: [https://github.com/ToschAutomatisering/PS-NCentral](https://github.com/ToschAutomatisering/PS-NCentral) 52 | 53 | Or installed from PS-Gallery with the cmdlet 54 | 55 | ```powershell 56 | Install-Module PS-NCentral 57 | ``` 58 | 59 | # Connecting 60 | 61 | The first step required before connecting is to create a new automation account with appropriate role permissions. With N-Central 2020 or 12.3 HF4 and later you must **disable the MFA** requirement for the account, so use a long and complex password. The (preferred) API-Only account in N-Central 2021 needs to be set to \'mfa not needed\'. 62 | 63 | Once the account is created, select the API Authentication tab and click on the ' **Generate JSON Web Token**' button, save this **JWT** token somewhere secure, if you lose your JWT, you can generate another one at any time, but it will invalidate the previous one. If you update/change role permissions for the account automation account you will need to regenerate the token, as the asserted permissions are in the JWT. 64 | 65 | Note: Activating the MFA-setting after generating the token still blocks JWT-access, as well as an expired password for the originating account (90 days default). 66 | 67 | ## PS-NCentral 68 | 69 | Connecting to your N-Central service with PS-NCentral only needs to be done once per session. You first require the following information: 70 | 71 | - The fqdn of your N-Central server, ie: `n-central.mydomain.com` 72 | - The JWT from above 73 | - Username/Password (no MFA) for versions **before 1.2**. 74 | 75 | Then enter the following: 76 | 77 | **All versions** 78 | 79 | ```powershell 80 | #Import the PS-NCentral module 81 | import-module .\PS-NCentral.psm1 -Verbose 82 | 83 | #$credential = Get-Credential ## This line can be used for a dialog. Skip 2 below. 84 | $password = ConvertTo-SecureString "" -AsPlainText -Force 85 | $credential = New-Object System.Management.Automation.PSCredential ("", $password) 86 | 87 | #Connect to NC 88 | New-NCentralConnection -ServerFQDN "YOUR SERVER FQDN" -PSCredential $credential 89 | ``` 90 | 91 | \* Might generate an error on some complex passwords. Avoid using a ^. 92 | 93 | **Version 1.2 and later** 94 | 95 | ```powershell 96 | #Import the PS-NCentral module 97 | import-module .\PS-NCentral.psm1 -Verbose 98 | 99 | #Connect to NC using the JWT directly 100 | New-NCentralConnection -ServerFQDN "YOUR SERVER FQDN" -JWT "YOUR JWT TOKEN" 101 | ``` 102 | 103 | which is equivalent to: 104 | 105 | ```powershell 106 | #Import the PS-NCentral module 107 | import-module .\PS-NCentral.psm1 -Verbose 108 | 109 | #Credentials with JWT 110 | $password = ConvertTo-SecureString "YOUR JWT TOKEN" -AsPlainText -Force 111 | $credential = New-Object System.Management.Automation.PSCredential ("_JWT", $password) 112 | 113 | #Connect to NC 114 | New-NCentralConnection -ServerFQDN "YOUR SERVER FQDN" -PSCredential $credential 115 | ``` 116 | If successful you will get an output similar to the below: 117 | 118 | |Property | Value| 119 | |--------|-----| 120 | | ConnectionURL | `n-central.mydomain.com` | 121 | | BindingURL | `https://n-central.mydomain.com/dms2/services2/ServerEI2?wsdl' | 122 | | AllProtocols | tls12,tls13 | 123 | | IsConnected | True | 124 | | RequestTimeOut | 100 | 125 | | NCVersion | 2020.1.5.425 | 126 | | DefaultCustomerID | 50 | 127 | | Error | | 128 | 129 | The session is now stored in the global **$\_NCSession** variable, and will automatically be used as default for following PS-NCentral commands. 130 | 131 | ### Multiple PS-NCentral server connections 132 | 133 | If you are an MSP with multiple N-Central servers, or have an NFC server for testing you can leverage the **-NCSession** parameter available on PS-NCentral cmdlets to quickly call other servers, this is available in all versions of PS-NCentral, but we'll use 1.2 as the example for brevity. 134 | 135 | Then enter the following: 136 | ```powershell 137 | #Connect to NC 138 | $Connection1 = New-NCentralConnection "$NCentralFQDN1" -JWT "$JWT1" 139 | $Connection2 = New-NCentralConnection "$NCentralFQDN2" -JWT "$JWT2" 140 | 141 | #Get the customer list from each server for later processing 142 | $NC1Customers = Get-NCCustomerList -NcSession $Connection1 143 | $NC2Customers = Get-NCCustomerList -NcSession $Connection2 144 | ``` 145 | 146 | Another useful pameter when connecting is the **DefaultCustomerID**, this sets the default scope for when calling cmdlets such as Get-NCDeviceList without a parameter, so if I were to perform the following connection and function call it would only give me all devices associated with CustomerID 333 147 | 148 | ``` powershell 149 | New-NCentralConnection "$NCentralFQDN" -JWT "$JWT1" -DefaultCustomerID 333 150 | $Customer333Devices = Get-NCDeviceList 151 | ``` 152 | 153 | You can use **Set-NCCustomerDefault** to change the value afterwards. 154 | 155 | ## PowerShell WebserviceProxy 156 | 157 | Notice the WebserviceProxy is discontinued after PowerShell version 5.1. You can find alternative code in [Appendix H - WebserviceProxy Alternative](#appendix-h---webserviceproxy-alternative) 158 | 159 | 160 | As a preface to the usage of the New-WebserviceProxy cmdlet, we will focus on the v2 rather than v1 legacy API as the v1 endpoint maybe deprecated at some point. 161 | 162 | The main differences between the v1 and v2 endpoints are: 163 | 164 | - The WSDL endpoint 165 | - Different classes, including the KeyPair constructor class used for adding custom settings for queries and update/change methods 166 | - V2 has all the newer methods available 167 | 168 | It will be necessary to review the Javadocs provided on your server for the lastest information on the classes and constructors, you can find them under your own N-Central server under `https://n-central.mydomain.com/dms/` 169 | 170 | If reviewing other WebserviceProxy powershell code on the internet, you can identify **v1**/legacy code as it will have the following in the binding URL string: **/dms/services/ServerEI?wsdl** while **v2** has **/dms2/services2/ServerEI2?wsdl** 171 | 172 | For connecting to webservice you will need the same information as with the PS-NCentral which connects in the same way underneath: 173 | 174 | - The fqdn of your N-Central server, ie: n-central.myserver.com 175 | - The JWT for the account 176 | 177 | With our examples we'll use v2 connections and classes, below is a common method seen in examples: 178 | ```powershell 179 | #Example host 180 | $serverHost = "n-central.myserver.com" 181 | 182 | # Bind to the namespace, using the Webserviceproxy 183 | $NWSNameSpace = "NAble" + ([guid]::NewGuid()).ToString().Substring(25) 184 | $bindingURL = "https://" + $serverHost + "/dms2/services2/ServerEI2?wsdl" 185 | $nws = New-Webserviceproxy $bindingURL -Namespace ($NWSNameSpace) 186 | ``` 187 | 188 | ```$NWSNameSpace``` here can be most anything of your choosing, the point of the GUID generation is to ensure the namespace for the classes to be used inside the webservice are _unique_ to anything else on your system or current context, you could use a static namespace such as MyNCentralConnection or PowerShellIsAwesome. 189 | 190 | After you've run this the $nws variable will contain all the available public methods from the endpoint, you can interrogate this by running 191 | ```powershell 192 | $nws | Get-Member 193 | ``` 194 | From this you will see a lot of | Event |s, Methods and Properties ie. 195 | 196 | |Name | MemberType | 197 | |----| ----------| 198 | |versionInfoGetCompleted || Event || 199 | | Abort| Method | 200 | | accessGroupAdd | Method | 201 | | BeginaccessGroupAdd | Method | 202 | | BeginaccessGroupGet | Method | 203 | 204 | 205 | The above output has been shortened, see [Appendix A – N-Central Web Service members](#appendix-a---n-central-web-service-members) members for the complete output. In addition you will have a **Definition** column, and you will observe that your `$NWSNameSpace` is seen prefixed to the methods/classes noted in them. All classes/methods/constructors available in the Javadocs can be created and called upon through the `$nws` variable. Eg. The customerListmethod would be called with 206 | 207 | ```powershell 208 | $nws.customerList("", $JWT, $settings) 209 | ``` 210 | 211 | As you will note when connecting with the `$nws` variable, at no point did you use your username or JWT, as you will observe in the `$nws.customerList` method called above, the $JWT is used in every get or set, and the username is simply `""` as the username is inside of the JWT string. 212 | 213 | Underneath the PS-NCentral module it saves these variables with each connection and re-uses each time a cmdlet is used. 214 | 215 | # Performing Queries 216 | 217 | ## PS-NCentral 218 | 219 | Performing queries with the PS-Central module is quick and easy, and several examples are provided in it's own documentation [here](https://github.com/ToschAutomatisering/PS-NCentral/blob/master/PS-NCentral_Examples.ps1) . The outcomes of the examples are fairly self explanatory. For our example we'll take a common query like the Customer table and join it with the Organisation properties table using the PS-NCentral cmdlets, then in the advanced section we'll give the same example using native cmdlets. 220 | ```powershell 221 | Import-Module PS-NCentral.psm1 -Verbose 222 | 223 | $ServerFQDN = n-central.myserver.com 224 | $JWT = "JWT TOKEN" 225 | 226 | #Connect to NC 227 | New-NCentralConnection -ServerFQDN $ServerFQDN -JWT $JWT 228 | 229 | #Grab the customer list/details 230 | $CustomerList = Get-NCCustomerList 231 | 232 | #Get the customer properties 233 | $CustomerPropertyList = Get-NCCustomerPropertyList 234 | 235 | #Create array list for table 236 | $CustomerReport = New-Object System.Collections.ArrayList 237 | 238 | #Merge 239 | foreach ($Customer in $CustomerList) { 240 | $Properties = $CustomerPropertyList | ?{$_.CustomerID -eq $Customer.customerid} 241 | $CustomerHashtable = [Ordered]@{} 242 | $Customer.psobject.properties | ?{$_.Name -ne 'customerid'} | %{$CustomerHashtable[$_.Name] = $_.Value} 243 | $PropertiesHashTable = [Ordered]@{} 244 | $Properties.psobject.properties | %{$PropertiesHashtable[$_.Name] = $_.Value} 245 | $ReportItem = $CustomerHashtable + $PropertiesHashTable 246 | $ReportItem = [PSCustomObject]$ReportItem 247 | $CustomerReport.Add($ReportItem) > $Null 248 | } 249 | 250 | #Output the report to the screen/Gridview 251 | $CustomerReport | Out-GridView 252 | ``` 253 | 254 | The important parts of this example are the simple one line calls for the **New-CentralConnection** , **Get-NCCustomerList** and **Get-NCCustomerPropertyList**. With very little effort we can connect, retrieve the data then process into a single table for review. 255 | 256 | ### Advanced PS-NCentral querying 257 | The PS-NCentral module provides ease of access to N-Central API calls with normal **verb-noun** functions, but you can also perform a direct call through the internal connection class. We could replace the above function calls with these methods: 258 | 259 | ```powershell 260 | # Connect to NC 261 | $NCSession = New-NCentralConnection -ServerFQDN $ServerFQDN -JWT $JWT 262 | 263 | # Grab the customer list/details 264 | $CustomerList = $NCSession.CustomerList() 265 | 266 | # Get the customer properties 267 | $CustomerPropertyList = $NCSession.OrganizationPropertyList() 268 | ``` 269 | 270 | We can get the list of all the underlying class connection methods by enumerating the members with `$_NCSession | Get-Member -MemberType Method` to see all 'inside' methods, which reflect the API-methods of N-Central ('http://mothership.n-able.com/dms/javadoc_ei2/com/nable/nobj/ei2/ServerEI2_PortType.html') where applicable. 271 | 272 | Most methods have 'Overloads'. These are selected based on the parameter-pattern eg. `([String], [String])` or `([String],[Int])`. 273 | 274 | ```powershell 275 | #Get the devices for customerid 100 276 | $Customer100Devices = $NCSession.DeviceList(100) 277 | #or 278 | $Customer100Devices = $NCSession.DeviceList(100,$true,$false) 279 | 280 | #Get the probes for customerid 100 281 | $Customer100Probes = $NCSession.DeviceList(100,$false,$true) 282 | ``` 283 | 284 | For a list of all methods see [Appendix E - All PS-Central Methods](#appendix-e---all-ps-central-methods) 285 | 286 | ## PowerShell WebserviceProxy 287 | 288 | In this section we'll perform the same example as above but using the native cmdlets we'll go through an example of a fully functioning cmdlet that uses native cmdlet calls. 289 | 290 | ```powershell 291 | # Define the command-line parameters to be used by the script 292 | [CmdletBinding()] 293 | Param( 294 | [Parameter(Mandatory = $true)]$serverHost, 295 | [Parameter(Mandatory = $true)]$JWT 296 | ) 297 | ``` 298 | 299 | Here we establish the mandatory variables we'll be using to connect, in this case the username of the automation account used, the server URI and the Java Web Token 300 | 301 | We'll then connect using a static namespace, you can equally use the pseudo-unique namespace above. 302 | 303 | ```powershell 304 | $NWSNameSpace = "NAbleAPI" 305 | ``` 306 | 307 | ### Bind to the namespace, using the Webserviceproxy 308 | ```powershell 309 | $bindingURL = "https://" + $serverHost + "/dms2/services2/ServerEI2?wsdl" 310 | $nws = New-Webserviceproxy $bindingURL -Namespace ($NWSNameSpace) 311 | ``` 312 | For many API calls a list of settings are required, in the case of the `CustomerList()` method we need to specify if the service organisation should be listed or not. The JavaDocs specify you have to use the `EiKeyValue` KeyPair type or array of `EiKeyValuesList` per the Javadocs, but it is simpler to create an ArrayList and add a generic hashtable Key/Pair that will be automatically cast to the `EiKeyValue`. 313 | 314 | ```powershell 315 | $settings = New-Object System.Collections.ArrayList 316 | $settings.Add(@{key = "listSOs"; value = "True" }) 317 | ``` 318 | 319 | Next we wrap the steps of retrieving the Customer List and Organisation properties list with a try/catch block that exits if there is an error with retrieving the data. 320 | ```powershell 321 | #Attempt to connect 322 | Try { 323 | $CustomerList = $nws.customerList("", $JWT, $Settings) 324 | $OrgPropertiesList = $nws.organizationPropertyList("", $JWT, $null, $false) 325 | } 326 | 327 | Catch { 328 | Write-Host Could not connect: $($_.Exception.Message) 329 | exit 330 | } 331 | ``` 332 | 333 | We then create a hash table of all the customer properties with the Customer ID as the Key and the Properties as the value. 334 | 335 | ```powershell 336 | $OrgPropertiesHashTable = @{} 337 | foreach ($Org in $OrgPropertiesList) { 338 | $CustomerOrgProps = @{} 339 | foreach ($p in $Org.properties) { $CustomerOrgProps[$p.label] = $p.value } 340 | $OrgPropertiesHashTable[$Org.customerId] = $CustomerOrgProps 341 | } 342 | ``` 343 | 344 | In the next step we take create an ArrayList in preference to a simple array to increase performance on inserts, then enumerate through the customer list match a custom list of tables and join it to the properties Hash table and output it to the screen. 345 | 346 | ```powershell 347 | #Create customer report ArrayList 348 | $CustomersReport = New-Object System.Collections.ArrayList 349 | 350 | ForEach ($Entity in $CustomerList) { 351 | $CustomerAssetInfo = @{} 352 | #Custom select the required columns, use Ordered to keep them in the order we list them in 353 | 354 | ForEach ($item in $Entity.items) { $CustomerAssetInfo[$item.key] = $item.Value } 355 | $o = [Ordered]@{ 356 | ID = $CustomerAssetInfo["customer.customerid"] 357 | Name = $CustomerAssetInfo["customer.customername"] 358 | parentID = $CustomerAssetInfo["customer.parentid"] 359 | RegistrationToken = $CustomerAssetInfo["customer.registrationtoken"] 360 | } 361 | 362 | #Retrieve the properties for the given customer ID 363 | $p = $OrgPropertiesHashTable[[int]$CustomerAssetInfo[customer.customerid]] 364 | 365 | #Merge the two hashtables 366 | $o = $o + $p 367 | 368 | #Cast the hashtable to a PSCustomObject 369 | $o = [PSCustomObject]$o 370 | 371 | #Add the PSCustomObject to our CustomersReport ArrayList 372 | $CustomersReport.Add($o) > $null 373 | } 374 | 375 | #Output to the screen 376 | $CustomersReport | Out-GridView 377 | ``` 378 | 379 | For the complete script see [Appendix C – GetAllCustomerProperties.ps1](#appendix-c---getallcustomerpropertiesps1) 380 | 381 | 382 | 383 | Note that **WebServiceProxy** is **discontinued** by Microsoft in PowerShell versions after 5.1. You can find alternative code in [Appendix H - WebserviceProxy Alternative](#appendix-h---webserviceproxy-alternative) 384 | 385 | 386 | # Updating a Value 387 | 388 | A common case for updating a value would be automating the update/change of Organisation or Device properties. Examples of Organisation properties could be: tokens/keys for MSP applications deployed to devices, the customer name to pass through to a script for output or the N-Central API registration token for installation of the agent. Updating these properties is straightforward with either the web proxy or PS-NCentral cmdlets. 389 | 390 | At time of writing the normal way for a Registration Token to be generated is through the UI, requiring an administrator to navigate to every _customer_ and every _site_ and click on the **Get Registration Token button** under **Download Agent/Probe** ; this will be changed in future. 391 | 392 | If you do need to perform mass registration token updating/refreshing there is an AMP provided as a part of the InstallAgent 6 suite that has a workaround and can be found at [https://github.com/AngryProgrammerInside/InstallAgent/tree/master/AMPs](https://github.com/AngryProgrammerInside/InstallAgent/tree/master/AMPs) 393 | 394 | ## PS-NCentral 395 | 396 | In the example for PS-NCentral we'll take the Customer name from the Get-NCCustomerList and inject it into _custom_ property called **Agent – Registration Token**, this is useful if we need to programmatically inject token information into files or registry settings for later use. We'll assume we already have a connection to N-Central: 397 | 398 | ```powershell 399 | $CustomerList = Get-NCCustomerList 400 | foreach ($Customer in $CustomerList){ 401 | Set-NCCustomerProperty -CustomerIDs $Customer.customerid -PropertyLabel "Agent - RegistrationToken" -PropertyValue $Customer.registrationtoken 402 | } 403 | ``` 404 | 405 | Or if we wanted to take the customer's name and inject it into a custom property like **Reporting – Customer Name** to inject it into an AMP's output for easier to identify the device AMPs run across a service organization: 406 | 407 | ```powershell 408 | $CustomerList = Get-NCCustomerList 409 | 410 | foreach ($Customer in $CustomerList){ 411 | Set-NCCustomerProperty -CustomerIDs $Customer.customerid -PropertyLabel "Reporting – Customer Name" -PropertyValue $Customer.customername 412 | } 413 | ``` 414 | An advantage of the Set-NCCustomerProperty cmdlet is that it can distinguish between the default _customer_ properties, ie. zip/postalcode, street1, externalid, externalid2 and will use the appropriate method to update that. You can find the list of key names in the Java Docs, or refer to **Appendix D – Customer Property variables**. 415 | 416 | For our example, you may have a PSA or perhaps a spreadsheet, and we want to refresh the information from that data source into _customer_ properties. In our example we'll use a spreadsheet/CSV as our datasource, and assume we have already matched the CustomerID with the company name and we have a dataset as below: 417 | 418 | | **customerid** | **firstname** | **lastname** | **email** | 419 | | --- | --- | --- | --- | 420 | | 1 | Claire | Young | Claire.Young@email.com | 421 | | 2 | Benjamin | Metcalfe | Bmetacalfe@usa.com | 422 | | 3 | Kimberly | King | kk@asia.com | 423 | | 4 | Michael | Mills | Mmills@engineer.com | 424 | | 5 | Anthony | Jackson | 008Jac@mail.com | 425 | 426 | \ 427 | You could then update the respective values in N-Central 428 | ```powershell 429 | $custData = Import-CSV C:\Temp\customerData.csv 430 | 431 | foreach ($Customer in $custData){ 432 | #Gather properties to update 433 | $Properties = $Customer.psobject.properties | ?{$_.Name -ne 'customerid'} 434 | 435 | foreach ($Property in $Properties){ 436 | #Update the property 437 | Set-NCCustomerProperty -CustomerIDs $Customer.customerid -PropertyLabel $Property -PropertyValue $Property.Value 438 | } 439 | } 440 | ``` 441 | ### Updating with pipelining 442 | Another advantage of PS-NCentral is that you can easily pipeline information through and set it as a customer property, in the first example we will update the **Reporting - Customer Name** again except this time utilising the pipe: 443 | ```powershell 444 | Get-NCCustomerList | Set-NCCustomerProperty -PropertyLabel 'Reporting – Customer Name' -PropertyValue $_.customername 445 | ``` 446 | 447 | In the second example we may have a custom table from a CSV or other source that has the following properties and values: 448 | 449 | | **customerid** | **CustomerSLA** | 450 | | --- | --- | 451 | | 123 | 1H | 452 | | 124 | 4H | 453 | | 221 | 8H | 454 | | 233 | 8H | 455 | | 321 | 8H | 456 | 457 | \ 458 | We then have this table in a variable `$CustomerProps` and use it to populate a custom property called **'Reporting - Customer SLA'** 459 | ```powershell 460 | Get-NCCustomerList | 461 | Select-Object customerid, @{n="CustomerSLA"; e={$CustomerID = $_.customerid; (@($CustomerProps).where({ $_.customerID -eq $CustomerID })).CustomerSLA}} ` 462 | | Where-Object {$_.CustomerSLA} ` 463 | | % { Set-NCCustomerProperty -CustomerIDs $_.CustomerID -PropertyLabel 'Reporting – Customer SLA' -PropertyValue ($_.CustomerSLA -join ',') } 464 | ``` 465 | When multiple records for a customerid are found in $Customerprops all values will be added comma-separated. 466 | 467 | The important parts of this example are the table-lookup 468 | 469 | ``` 470 | (@().where( -eq )). 471 | ``` 472 | 473 | and the filter to only return objects which had values added 474 | 475 | ``` 476 | Where-Object {$_.} 477 | ``` 478 | 479 | before setting the properties. 480 | 481 | ### Updating Custom Device Properties 482 | Another example would be where we may want to populate a Custom Device Property, in this case **'External ID'** based upon the CustomerID using in a customer table `$Customers` 483 | | **customerid** | **ExternalID** | 484 | | --- | --- | 485 | | 123 | 78409377 | 486 | | 124 | 78405890 | 487 | | 221 | 78404905 | 488 | | 233 | 78402984 | 489 | | 321 | 38940384 | 490 | 491 | ```powershell 492 | Get-NCDeviceList | ` 493 | Select-Object DeviceID, ` 494 | @{n="ExternalID"; e={$CustomerID = $_.customerid; (@($Customers).where({ $_.customerID -eq $CustomerID })).ExternalID}} | ` 495 | Where-Object {$_.ExternalID} | %{Set-NCDeviceProperty -DeviceIDs $_.DeviceID -PropertyLabel 'ExternalID' -PropertyValue ($_.ExternalID -join ',')} 496 | ``` 497 | 498 | 499 | 500 | ### Custom Property options 501 | 502 | These options are introduced in PS-NCentral version **1.3**. 503 | 504 | #### Encoding 505 | 506 | Use the **-Base64** option to Encode/Decode a CustomProperty when using Set or Get. Unicode (utf16) by default, -utf8 option available. 507 | 508 | **Convert-Base64** is available as a seperate command too. 509 | 510 | 511 | 512 | #### Comma-Separated Values 513 | 514 | When a Custom Property holds a string of (unique) Comma-seperated values you can easily Add or Remove a single value with the commands: 515 | 516 | - Add-NCCustomerPropertyValue 517 | - Add-NCDevicePropertyValue 518 | - Remove-NCCustomerPropertyValue 519 | - Remove-NCDevicePropertyValue 520 | 521 | Use Get-help \ to see the options. 522 | 523 | 524 | 525 | #### Format-properties 526 | 527 | Sometimes not all objects in a list have the same properties. This can become an issue when using **Format-Table** or **Output-CSV**, which only use the properties of the first object in the list. 528 | 529 | The **Format-Properties** cmdlet ensures all unique properties are added to all objects in a list. It is integrated in several PS-NCentral list-commands but also available as a seperate command. 530 | 531 | 532 | 533 | ## PowerShell WebserviceProxy 534 | 535 | Updating customer properties and without the PS-NCentral cmdlets can take several additional steps as PS-NCentral takes care of some busy work underneath. 536 | 537 | ### Registration token injection 538 | 539 | Let's first take the example of injecting taking the registration token from the **customerList** method and injecting it via the **organizationPropertyModify** method. As above we'll assume we have a connection `$nws` already and our list of customers is in the variable $CustomerList, take note of the line where gathering the value of the custom property with the id **123456789**. 540 | ```powershell 541 | ForEach ($Entity in $CustomerList) { 542 | $CustomerAssetInfo = @{} 543 | ForEach ($item in $Entity.items) { $CustomerAssetInfo[$item.key] = $item.Value } 544 | 545 | #Create a custom object for the data 546 | $CustomerObject = [Ordered]@{ 547 | ID = $CustomerAssetInfo[customer.customerid] 548 | Name = $CustomerAssetInfo[customer.customername] 549 | parentID = $CustomerAssetInfo[customer.parentid] 550 | RegistrationToken = $CustomerAssetInfo[customer.registrationtoken] 551 | } 552 | 553 | #Skip any Registration tokens that are null/empty 554 | if ($null -eq $CustomerObject.RegistrationToken -or -eq $CustomerObject.RegistrationToken) {continue} 555 | 556 | #Gather the property value for the specific property ID 557 | $CustomerProperty = ($OrgPropertiesList | ?{$_.customerId -eq $CustomerObject.ID}).properties | ?{$_.propertyid -eq 123456789} 558 | $CustomerProperty.value = $CustomerObject.RegistrationToken 559 | 560 | #Create a new OrganizationProperties object and populate it 561 | $ModOrgProperties = New-Object $NWSNameSpace.OrganizationProperties 562 | $ModOrgProperties.customerId = $CustomerObject.ID 563 | $ModOrgProperties.customerIdSpecified = $true 564 | $ModOrgProperties.properties = $CustomerProperty 565 | 566 | #Inject the property 567 | $nws.organizationPropertyModify("",$JWT,$ModOrgProperties) 568 | } 569 | ``` 570 | ### Gather organization property ID 571 | 572 | While the above code works in updating the specific customer org property, one must first interrogate the properties and their associated values in advance. While this is fine for scripts where you will always be updating the same **propertyid** , you may wish to implement a function that takes care of searching and retrieving the **propertyid**. 573 | 574 | PS-NCentral cmdlets use a class to retrieve this, we can convert it to a function for our use: 575 | ```powershell 576 | function Get-OrganizationPropertyID( 577 | [Int]$OrganizationID, 578 | [String]$PropertyName, 579 | [String]$JWT, 580 | [System.Web.Services.Protocols.SoapHttpClientProtocol]$NcConnection){ 581 | 582 | ## Returns 0 (zero) if not found. 583 | $OrganizationPropertyID = 0 584 | $results = $null 585 | Try{ 586 | #Gets the organization and all custom properties 587 | $results = $NcConnection.OrganizationPropertyList("", $JWT, $OrganizationID, $false) 588 | } 589 | Catch { 590 | $_.ErrorHandler 591 | } 592 | 593 | #Search through all properties and match the one with the same name 594 | ForEach ($OrganizationProperty in $results.properties){ 595 | If($OrganizationProperty.label -eq $PropertyName){ 596 | $OrganizationPropertyID = $OrganizationProperty.PropertyID 597 | } 598 | } 599 | Return $OrganizationPropertyID 600 | } 601 | ``` 602 | We can then use the function to gather the property ID 603 | 604 | ```powershell 605 | #Get the property id for org 123 with the property name Agent – Registration token 606 | Get-OrganizationPropertyID -OrganizationID 123 -PropertyName "Agent - Registration Token" -JWT $JWT -NcConnection $nws 607 | ``` 608 | 609 | The author notes that at time of writing, the **propertyid** appears to be the same for all customers/sites created at the same hierarchical level (System/SO/Customer/Site). For cases where you have multiple service organizations with the same named custom property created at the SO level they should be a different propertyid. 610 | 611 | For single SO deployments where the custom properties are created at the SO level they are globally unique, you could also create a lookup table for optimising your code to avoid performing a **propertyid** lookup for each update of a custom property, though we won't be covering that in this document. 612 | 613 | ### Update customer property 614 | 615 | Updating a _customer_ property such as the contact details or externalid values is done through the **customerModify** method, the method is called with the form: 616 | 617 | ```customerModify([string]username,[string]password,[ListEiKeyValue]settings)``` 618 | 619 | You may note in the PS-NCentral example it can update one property, either *custom* or customer, in a single call; whereas the KeyValue list can contain one or all of the customer values shown in [Appendix D – Customer Property variables](#appendix-d---customer-property-variables) to be updated in a single call. 620 | 621 | We'll use an expanded data set from the PS-NCentral as we have more mandatory fields **customername** , **customerid** and **parentid** that are otherwise looked up by an internal helper function in PS-NCentral: 622 | 623 | | parentid | customerid | customername | firstname | lastname | email | 624 | | --- | --- | --- | --- | --- | --- | 625 | | 50 | 1 | Contoso | Claire | Young | `Claire.Young@email.com` | 626 | | 50 | 2 | Volcano Coffee | Benjamin | Metcalfe | `Bmetacalfe@usa.com` | 627 | | 50 | 3 | Northwind Traders | Kimberly | King | `kk@asia.com` | 628 | | 50 | 4 | WW Importers | Michael | Mills | `Mmills@engineer.com` | 629 | | 50 | 5 | Blue Yonder | Anthony | Jackson | `008Jac@mail.com` | 630 | 631 | You can retrieve the mandatory fields mentioned in the above table by using the `CustomerList()` covered previously. 632 | 633 | In the below example the data is imported, then we generate the appropriate KeyValue array and assuming use the same $nwsconnection variable and $NWSNameSpace from previous examples to connect and update the modified keys. 634 | ```powershell 635 | $custData = Import-CSV C:\Temp\customerData.csv 636 | foreach ($Customer in $custData){ 637 | #Gather properties to update 638 | $Properties = $Customer.psobject.properties 639 | #Create an Arraylist of HashTables to update 640 | $ModifiedKeyList = New-Object System.Collections.ArrayList 641 | $Properties | ForEach-Object{ 642 | $KeyPair = @{} 643 | $KeyPair.key = $_.Name 644 | $KeyPair.value = $_.Value 645 | $ModifiedKeyList.Add($KeyPair) 646 | } 647 | $nws.customerModify("",$JWT,$ModifiedKeyList) 648 | } 649 | ``` 650 | ### Add new a new Customer 651 | 652 | Not every cmdlet is currently available in PS-NCentral, one such cmdlet that could be useful is the automation of the creation of customer accounts. In the below example we use the ```$nws``` connection from before and pass through a hashtable of some of the customer properties in in [Appendix D – Customer Property variables](#appendix-d---customer-property-variables), note there are two required fields: **customername** and **parentid** 653 | 654 | Combining the hashtable `$newcustomer` with the `$JWT` and `$nws` to the cmdlet it will create the customer. It will return the new CustomerID value once the job is completed. 655 | ```powershell 656 | $newcustomer = @{ 657 | customername = "New Customer" 658 | parentid = "50" 659 | firstname = "john" 660 | lastname = "doe" 661 | email = "john.doe@contoso.com" 662 | city = "Melbourne" 663 | telephone = "0312345678" 664 | country = "AU" 665 | } 666 | 667 | function Add-NCCustomer( 668 | [Hashtable]$CustomerTable, 669 | [String]$JWT, 670 | [System.Web.Services.Protocols.SoapHttpClientProtocol]$NcConnection) { 671 | $CustomerAttributeList = New-Object System.Collections.ArrayList 672 | foreach ($key in $CustomerTable.Keys){ 673 | $setting = @{key = $key; value = $CustomerTable[$key]} 674 | $CustomerAttributeList.Add($setting) > $null 675 | } 676 | $NcConnection.customerAdd("", $JWT, $CustomerAttributeList) 677 | } 678 | 679 | Add-NCCustomer -CustomerTable $newcustomer -JWT $JWT -NcConnection $nws 680 | ``` 681 | 682 | At time of writing with PS-NCentral version 1.2 it is possible to use the CustomerAdd() method as it is exists inside the core class object now. While there is currently no Powershell function to call this, create a customer with it in the following way: 683 | 684 | ```powershell 685 | #Connect to NC 686 | $NCSession = New-NCentralConnection -ServerFQDN n-central.myserver.com -JWT $JWT 687 | $ParentId = 50 688 | $NewCustomerAttributes = @{ 689 | firstname = "john" 690 | lastname = "doe" 691 | email = "john.doe@contoso.com" 692 | city = "Melbourne" 693 | telephone = "0312345678" 694 | country = "AU" 695 | } 696 | 697 | $NCSession.CustomerAdd("NewCustomerName",$ParentId,$NewCustomerAttributes) 698 | ``` 699 | You can also create the customer without attributes and fill them out later if you wish by simply calling `$NCSession.CustomerAdd("NewCustomerName",$ParentId)` 700 | 701 | This function will return the value for the new Customer ID, you can then use that Id to perform further automation if needed. 702 | 703 | # Appendix A – N-Central Web Service members 704 | 705 | |Name |MemberType| 706 | |---- |----------| 707 | |accessGroupAddCompleted | Event | 708 | |accessGroupGetCompleted | Event | 709 | |accessGroupListCompleted | Event | 710 | |acknowledgeNotificationCompleted | Event | 711 | |activeIssuesListCompleted | Event | 712 | |customerAddCompleted | Event | 713 | |customerDeleteCompleted | Event | 714 | |customerListChildrenCompleted | Event | 715 | |customerListCompleted | Event | 716 | |customerModifyCompleted | Event | 717 | |deviceAssetInfoExportDeviceCompleted | Event | 718 | |deviceAssetInfoExportDeviceWithSettingsCompleted | Event | 719 | |deviceGetCompleted | Event | 720 | |deviceGetStatusCompleted | Event | 721 | |deviceListCompleted | Event | 722 | |devicePropertyListCompleted | Event | 723 | |devicePropertyModifyCompleted | Event | 724 | |Disposed | Event | 725 | |jobStatusListCompleted | Event | 726 | |lastExportResetCompleted | Event | 727 | |organizationPropertyListCompleted | Event | 728 | |organizationPropertyModifyCompleted | Event | 729 | |psaCreateCustomTicketCompleted | Event | 730 | |psaCredentialsValidateCompleted | Event | 731 | |psaGetCustomTicketCompleted | Event | 732 | |psaReopenCustomTicketCompleted | Event | 733 | |psaResolveCustomTicketCompleted | Event | 734 | |SOAddCompleted | Event | 735 | |taskPauseMonitoringCompleted | Event | 736 | |taskResumeMonitoringCompleted | Event | 737 | |userAddCompleted | Event | 738 | |userRoleAddCompleted | Event | 739 | |userRoleGetCompleted | Event | 740 | |userRoleListCompleted | Event | 741 | |versionInfoGetCompleted | Event | 742 | |Abort | Method | 743 | |accessGroupAdd | Method | 744 | |accessGroupAddAsync | Method | 745 | |accessGroupGet | Method | 746 | |accessGroupGetAsync | Method | 747 | |accessGroupList | Method | 748 | |accessGroupListAsync | Method | 749 | |acknowledgeNotification | Method | 750 | |acknowledgeNotificationAsync | Method | 751 | |activeIssuesList | Method | 752 | |activeIssuesListAsync | Method | 753 | |BeginaccessGroupAdd | Method | 754 | |BeginaccessGroupGet | Method | 755 | |BeginaccessGroupList | Method | 756 | |BeginacknowledgeNotification | Method | 757 | |BeginactiveIssuesList | Method | 758 | |BegincustomerAdd | Method | 759 | |BegincustomerDelete | Method | 760 | |BegincustomerList | Method | 761 | |BegincustomerListChildren | Method | 762 | |BegincustomerModify | Method | 763 | |BegindeviceAssetInfoExportDevice | Method | 764 | |BegindeviceAssetInfoExportDeviceWithSettings | Method | 765 | |BegindeviceGet | Method | 766 | |BegindeviceGetStatus | Method | 767 | |BegindeviceList | Method | 768 | |BegindevicePropertyList | Method | 769 | |BegindevicePropertyModify | Method | 770 | |BeginjobStatusList | Method | 771 | |BeginlastExportReset | Method | 772 | |BeginorganizationPropertyList | Method | 773 | |BeginorganizationPropertyModify | Method | 774 | |BeginpsaCreateCustomTicket | Method | 775 | |BeginpsaCredentialsValidate | Method | 776 | |BeginpsaGetCustomTicket | Method | 777 | |BeginpsaReopenCustomTicket | Method | 778 | |BeginpsaResolveCustomTicket | Method | 779 | |BeginSOAdd | Method | 780 | |BegintaskPauseMonitoring | Method | 781 | |BegintaskResumeMonitoring | Method | 782 | |BeginuserAdd | Method | 783 | |BeginuserRoleAdd | Method | 784 | |BeginuserRoleGet | Method | 785 | |BeginuserRoleList | Method | 786 | |BeginversionInfoGet | Method | 787 | |CancelAsync | Method | 788 | |CreateObjRef | Method | 789 | |customerAdd | Method | 790 | |customerAddAsync | Method | 791 | |customerDelete | Method | 792 | |customerDeleteAsync | Method | 793 | |customerList | Method | 794 | |customerListAsync | Method | 795 | |customerListChildren | Method | 796 | |customerListChildrenAsync | Method | 797 | |customerModify | Method | 798 | |customerModifyAsync | Method | 799 | |deviceAssetInfoExportDevice | Method | 800 | |deviceAssetInfoExportDeviceAsync | Method | 801 | |deviceAssetInfoExportDeviceWithSettings | Method | 802 | |deviceAssetInfoExportDeviceWithSettingsAsync | Method | 803 | |deviceGet | Method | 804 | |deviceGetAsync | Method | 805 | |deviceGetStatus | Method | 806 | |deviceGetStatusAsync | Method | 807 | |deviceList | Method | 808 | |deviceListAsync | Method | 809 | |devicePropertyList | Method | 810 | |devicePropertyListAsync | Method | 811 | |devicePropertyModify | Method | 812 | |devicePropertyModifyAsync | Method | 813 | |Discover | Method | 814 | |Dispose | Method | 815 | |EndaccessGroupAdd | Method | 816 | |EndaccessGroupGet | Method | 817 | |EndaccessGroupList | Method | 818 | |EndacknowledgeNotification | Method | 819 | |EndactiveIssuesList | Method | 820 | |EndcustomerAdd | Method | 821 | |EndcustomerDelete | Method | 822 | |EndcustomerList | Method | 823 | |EndcustomerListChildren | Method | 824 | |EndcustomerModify | Method | 825 | |EnddeviceAssetInfoExportDevice | Method | 826 | |EnddeviceAssetInfoExportDeviceWithSettings | Method | 827 | |EnddeviceGet | Method | 828 | |EnddeviceGetStatus | Method | 829 | |EnddeviceList | Method | 830 | |EnddevicePropertyList | Method | 831 | |EnddevicePropertyModify | Method | 832 | |EndjobStatusList | Method | 833 | |EndlastExportReset | Method | 834 | |EndorganizationPropertyList | Method | 835 | |EndorganizationPropertyModify | Method | 836 | |EndpsaCreateCustomTicket | Method | 837 | |EndpsaCredentialsValidate | Method | 838 | |EndpsaGetCustomTicket | Method | 839 | |EndpsaReopenCustomTicket | Method | 840 | |EndpsaResolveCustomTicket | Method | 841 | |EndSOAdd | Method | 842 | |EndtaskPauseMonitoring | Method | 843 | |EndtaskResumeMonitoring | Method | 844 | |EnduserAdd | Method | 845 | |EnduserRoleAdd | Method | 846 | |EnduserRoleGet | Method | 847 | |EnduserRoleList | Method | 848 | |EndversionInfoGet | Method | 849 | |Equals | Method | 850 | |GetHashCode | Method | 851 | |GetLifetimeService | Method | 852 | |GetType | Method | 853 | |InitializeLifetimeService | Method | 854 | |jobStatusList | Method | 855 | |jobStatusListAsync | Method | 856 | |lastExportReset | Method | 857 | |lastExportResetAsync | Method | 858 | |organizationPropertyList | Method | 859 | |organizationPropertyListAsync | Method | 860 | |organizationPropertyModify | Method | 861 | |organizationPropertyModifyAsync | Method | 862 | |psaCreateCustomTicket | Method | 863 | |psaCreateCustomTicketAsync | Method | 864 | |psaCredentialsValidate | Method | 865 | |psaCredentialsValidateAsync | Method | 866 | |psaGetCustomTicket | Method | 867 | |psaGetCustomTicketAsync | Method | 868 | |psaReopenCustomTicket | Method | 869 | |psaReopenCustomTicketAsync | Method | 870 | |psaResolveCustomTicket | Method | 871 | |psaResolveCustomTicketAsync | Method | 872 | |SOAdd | Method | 873 | |SOAddAsync | Method | 874 | |taskPauseMonitoring | Method | 875 | |taskPauseMonitoringAsync | Method | 876 | |taskResumeMonitoring | Method | 877 | |taskResumeMonitoringAsync | Method | 878 | |ToString | Method | 879 | |userAdd | Method | 880 | |userAddAsync | Method | 881 | |userRoleAdd | Method | 882 | |userRoleAddAsync | Method | 883 | |userRoleGet | Method | 884 | |userRoleGetAsync | Method | 885 | |userRoleList | Method | 886 | |userRoleListAsync | Method | 887 | |versionInfoGet | Method | 888 | |versionInfoGetAsync | Method | 889 | |AllowAutoRedirect | Property | 890 | |ClientCertificates | Property | 891 | |ConnectionGroupName | Property | 892 | |Container | Property | 893 | |CookieContainer | Property | 894 | |Credentials | Property | 895 | |EnableDecompression | Property | 896 | |PreAuthenticate | Property | 897 | |Proxy | Property | 898 | |RequestEncoding | Property | 899 | ||Site | Property | 900 | |SoapVersion | Property | 901 | |Timeout | Property | 902 | |UnsafeAuthenticatedConnectionSharing | Property | 903 | |Url | Property | 904 | |UseDefaultCredentials | Property | 905 | |UserAgent | Property | 906 | 907 | # Appendix B - PS-NCentral cmdlets 908 | 909 | | Command | Synopsis | 910 | | --- | --- | 911 | | Get-NCAccessGroupList | Returns the list of AccessGroups at the specified CustomerID level. | 912 | | Get-NCActiveIssuesList | Returns the Active Issues on the CustomerID-level and below. | 913 | | Get-NCCustomerList | Returns a list of all customers and their data. ChildrenOnly when CustomerID is specified. | 914 | | Get-NCCustomerPropertyList | Returns a list of all Custom-Properties for the selected CustomerID(s). | 915 | | Get-NCDeviceID | Returns the DeviceID(s) for the given DeviceName(s). Case Sensitive, No Wildcards. | 916 | | Get-NCDeviceInfo | Returns the General details for the DeviceID(s). | 917 | | Get-NCDeviceList | Returns the Managed Devices for the given CustomerID(s) and Sites below. | 918 | | Get-NCDeviceLocal | Returns the DeviceID, CustomerID and some more Info for the Local Computer. | 919 | | Get-NCDeviceObject | Returns a Device and all asset-properties as an object. | 920 | | Get-NCDevicePropertyList | Returns the Custom Properties of the DeviceID(s). | 921 | | Get-NCDevicePropertyListFilter | Returns the Custom Properties of the Devices within the Filter(s). | 922 | | Get-NCDeviceStatus | Returns the Services for the DeviceID(s). | 923 | | Get-NCHelp | Shows a list of available PS-NCentral commands and the synopsis. | 924 | | Get-NCJobStatusList | Returns the Scheduled Jobs on the CustomerID-level and below. | 925 | | Get-NCProbeList | Returns the Probes for the given CustomerID(s). | 926 | | Get-NCServiceOrganizationList | Returns a list of all ServiceOrganizations and their data. | 927 | | Get-NCTimeOut | Returns the max. time in seconds to wait for data returning from a (Synchronous) NCentral API-request. | 928 | | Get-NCUserRoleList | Returns the list of Roles at the specified CustomerID level. | 929 | | NcConnected | Checks or initiates the NCentral connection. | 930 | | New-NCentralConnection | Connect to the NCentral server. | 931 | | Set-NCCustomerProperty | Fills the specified property(name) for the given CustomerID(s). | 932 | | Set-NCDeviceProperty | Fills the Custom Property for the DeviceID(s). | 933 | | Set-NCTimeOut | Sets the max. time in seconds to wait for data returning from a (Synchronous) NCentral API-request. | 934 |
935 | 936 | # Appendix C – GetAllCustomerProperties.ps1 937 | 938 | ```powershell 939 | # Define the command-line parameters to be used by the script 940 | [CmdletBinding()] 941 | Param( 942 | [Parameter(Mandatory = $true)]$serverHost, 943 | [Parameter(Mandatory = $true)]$JWT 944 | ) 945 | # Generate a pseudo-unique namespace to use with the New-WebServiceProxy 946 | $NWSNameSpace = NAble + ([guid]::NewGuid()).ToString().Substring(25) 947 | 948 | # Bind to the namespace, using the Webserviceproxy 949 | $bindingURL = "https://" + $serverHost + "/dms2/services2/ServerEI2?wsdl" 950 | $nws = New-Webserviceproxy $bindingURL -Namespace ($NWSNameSpace) 951 | 952 | # Set up and execute the query 953 | $Settings = New-Object System.Collections.ArrayList 954 | $Settings.Add(@{key = "listSOs"; value = "True" }) 955 | 956 | #Attempt to connect 957 | Try { 958 | $CustomerList = $nws.customerList("", $JWT, $Settings) 959 | $OrgPropertiesList = $nws.organizationPropertyList("", $JWT, $null, $false) 960 | } 961 | Catch { 962 | Write-Host Could not connect: $($_.Exception.Message) 963 | exit 964 | } 965 | 966 | $OrgPropertiesHashTable = @{} 967 | foreach ($Org in $OrgPropertiesList) { 968 | $CustomerOrgProps = @{} 969 | foreach ($p in $Org.properties) { $CustomerOrgProps[$p.label] = $p.value } 970 | $OrgPropertiesHashTable[$Org.customerId] = $CustomerOrgProps 971 | 972 | } 973 | 974 | #Create customer report ArrayList 975 | $CustomersReport = New-Object System.Collections.ArrayList 976 | ForEach ($Entity in $CustomerList) { 977 | $CustomerAssetInfo = @{} 978 | 979 | #Custom select the required columns, us Ordered to keep them in the order we list them in 980 | ForEach ($item in $Entity.items) { $CustomerAssetInfo[$item.key] = $item.Value } 981 | $o = [Ordered]@{ 982 | ID = $CustomerAssetInfo[customer.customerid] 983 | Name = $CustomerAssetInfo[customer.customername] 984 | parentID = $CustomerAssetInfo[customer.parentid] 985 | RegistrationToken = $CustomerAssetInfo[customer.registrationtoken] 986 | } 987 | 988 | #Retrieve the properties for the given customer ID 989 | $p = $OrgPropertiesHashTable[[int]$CustomerAssetInfo[customer.customerid]] 990 | 991 | #Merge the two hashtables 992 | $o = $o + $p 993 | #Cast the hashtable to a PSCustomObject 994 | $o = [PSCustomObject]$o 995 | 996 | #Add the PSCustomObject to our CustomersReport ArrayLIst 997 | $CustomersReport.Add($o) > $null 998 | } 999 | 1000 | #Output to the screen 1001 | $CustomersReport | Out-GridView 1002 | ``` 1003 | 1004 | # Appendix D – Customer Property variables 1005 | 1006 | These are the default properties returned in the customerlist. After connecting using PS-NCentral this list can also be found in the customervalidation property. 1007 | 1008 | ```powershell 1009 | $_ncsession.customervalidation 1010 | ``` 1011 | 1012 | - **postalcode** - (Value) Customer's zip/ postal code. 1013 | - **street1** - (Value) Address line 1 for the customer. Maximum of 100 characters. 1014 | - **street2** - (Value) Address line 2 for the customer. Maximum of 100 characters. 1015 | - **city** - (Value) Customer's city. 1016 | - **stateprov** - (Value) Customer's state/ province. 1017 | - **phone** - (Value) Phone number of the customer. 1018 | - **country** - (Value) Customer's country. Two character country code, see http://en.wikipedia.org/wiki/ISO\_3166-1\_alpha-2 for a list of country codes. 1019 | - **externalid** - (Value) An external reference id. 1020 | - **externalid2** - (Value) A second external reference id. 1021 | - **contactfirstname** - (Value) Customer contact's first name. 1022 | - **contactlastname** - (Value) Customer contact's last name. 1023 | - **contacttitle** - (Value) Customer contact's title. 1024 | - **contactdepartment** - (Value) Customer contact's department. 1025 | - **contactphonenumber** - (Value) Customer contact's telephone number. 1026 | - **contactext** - (Value) Customer contact's telephone extension. 1027 | - **contactemail** - (Value) Customer contact's email. Maximum of 100 characters. 1028 | - **registrationtoken** - (ReadOnly) For agent/probe-install validation. 1029 | - **licensetype** - (Value) The default license type of new devices for the customer. Must be Professional or Essential. Default is Essential. 1030 | 1031 | # Appendix E - All PS-Central Methods 1032 | | Name | 1033 | | --- | 1034 | |AccessGroupGet| 1035 | |AccessGroupList| 1036 | |ActiveIssuesList| 1037 | |Connect| 1038 | |CustomerAdd| 1039 | |CustomerList| 1040 | |CustomerListChildren| 1041 | |CustomerModify| 1042 | |DeviceAssetInfoExportDevice| 1043 | |DeviceAssetInfoExportDeviceWithSettings| 1044 | |DeviceGet| 1045 | |DeviceGetAppliance| 1046 | |DeviceGetStatus| 1047 | |DeviceList| 1048 | |DevicePropertyID| 1049 | |DevicePropertyList| 1050 | |DevicePropertyModify| 1051 | |Equals| 1052 | |ErrorHandler| 1053 | |GetHashCode| 1054 | |GetType| 1055 | |JobStatusList| 1056 | |OrganizationPropertyID| 1057 | |OrganizationPropertyList| 1058 | |OrganizationPropertyModify| 1059 | |ProcessData1| 1060 | |ProcessData2| 1061 | |ToString| 1062 | |UserRoleGet| 1063 | |UserRoleList| 1064 | 1065 | # Appendix F - Common Error Codes 1066 | 1067 | \# Connection-error (https): There was an error downloading .. 1068 | 1069 | \# 1012 - Thrown when mandatory settings are not present in "settings". 1070 | 1071 | \# 2001 - Required parameter is null - Thrown when null values are entered as inputs. 1072 | 1073 | \# 2001 - Unsupported version - Thrown when a version not specified above is entered as input. 1074 | 1075 | \# 2001 - Thrown when a bad username-password combination is input, or no PSA integration has been set up. 1076 | 1077 | \# 2100 - Thrown when invalid MSP N-central credentials are input. 1078 | 1079 | \# 2100 - Thrown when MSP-N-central credentials with MFA are used. 1080 | 1081 | \# 3010 - Maximum number of users reached. 1082 | 1083 | \# 3012 - Specified email address is already assigned to another user. 1084 | 1085 | \# 3014 - Creation of a user for the root customer (CustomerID 1) is not permitted. 1086 | 1087 | \# 3014 - When adding a user, must not be an LDAP user. 1088 | 1089 | \# 3020 - Account is locked 1090 | 1091 | \# 3022 - Customer/Site already exists. 1092 | 1093 | \# 3026 - Customer name length has exceeded 120 characters. 1094 | 1095 | \# 4000 - SessionID not found or has expired. 1096 | 1097 | \# 5000 - An unexpected exception occurred. 1098 | 1099 | \# 5000 - Query failed. 1100 | 1101 | \# 5000 - javax.validation.ValidationException: Unable to validate UI session --> often an expired password, even when using JWT. 1102 | 1103 | \# 9910 - Service Organization already exists. 1104 | 1105 | 1106 | 1107 | # Appendix G - Issue Status 1108 | 1109 | These codes can be used with the **-IssueStatus** option of the **Get-NCActiveIssuesList** command. In v1.3 code 1 and 5 naming was incorrect (swapped) 1110 | 1111 | ``` 1112 | 1 No Data 1113 | 2 Stale 1114 | 3 Normal --> Nothing returned 1115 | 4 Warning 1116 | 5 Failed 1117 | 6 Misconfigured 1118 | 7 Disconnected 1119 | 1120 | 11 Unacknowledged 1121 | 12 Acknowledged 1122 | ``` 1123 | 1124 | The API does not allow combinations of these filters. 1125 | 1126 | - **1-7** are reflected in the **notifstate**-property. 1127 | - **11** and **12** relate to the properties **numberofactivenotification** and **numberofacknowledgednotification**. 1128 | 1129 | 1130 | 1131 | # Appendix H - WebserviceProxy Alternative 1132 | 1133 | The command **WebServiceProxy** is **discontinued** by Microsoft in PowerShell versions after 5.1. Below you can find an example of retrieving data with **Invoke-RestMethod** and compare it to the use of WebserviceProxy. 1134 | 1135 | ```PowerShell 1136 | ## Retrieving data from N-Central by SOAP-API 1137 | 1138 | # Settings 1139 | $Servername = "ServerFQDN" 1140 | $UserName = "API-User-noMFA" ## Or "" when using JWT 1141 | $Password = "P@ssword" ## Or JWT (preferred) 1142 | 1143 | # Function for retrieving data without Webserviceproxy. 1144 | # Works for most (but not all!!) Methods in 1145 | # https://mothership.n-able.com/dms/javadoc_ei2/com/nable/nobj/ei2/ServerEI2_PortType.html 1146 | # Note: Complex passwords may contain characters that invalidate the SOAP-request. 1147 | Function GetNCData([String]$APIMethod,[String]$Username,[String]$PassOrJWT,$KeyPairs){ 1148 | 1149 | ## Process Keys 1150 | $MyKeys="" 1151 | ForEach($KeyPair in $KeyPairs){ 1152 | $MyKeys = $MyKeys + (" 1153 | 1154 | {0} 1155 | {1} 1156 | " -f ($KeyPair.Key),($KeyPair.Value)) 1157 | } 1158 | 1159 | ## Build SoapRequest (last line must be left-lined for terminating @") 1160 | $MySoapRequest =(@" 1161 | 1162 | 1163 | 1164 | 1165 | {1} 1166 | {2}{3} 1167 | 1168 | 1169 | 1170 | "@ -f $APIMethod, $Username, $PassOrJWT, $MyKeys) 1171 | #Write-Host $MySoapRequest ## For Debug/Educational purpose 1172 | 1173 | ## Request DataSet 1174 | $FullResponse = $null 1175 | Try{ 1176 | $FullResponse = Invoke-RestMethod -Uri $BindingURL -body $MySoapRequest -Method POST 1177 | } 1178 | Catch{ 1179 | Write-Host ("Could not connect: {0}." -f $_.Exception.Message ) 1180 | exit 1181 | } 1182 | 1183 | ## Process Returned DataSet 1184 | $ReturnClass = $FullResponse.envelope.body | Get-Member -MemberType Property 1185 | $ReturnProperty = $ReturnClass[0].Name 1186 | 1187 | Return $FullResponse.envelope.body.$ReturnProperty.return 1188 | } 1189 | # End of Function GetNCData 1190 | 1191 | #Start of Main Script 1192 | # Extract local configuration Info. 1193 | $ApplianceConfig = ("{0}\N-able Technologies\Windows Agent\config\ApplianceConfig.xml" -f ${Env:ProgramFiles(x86)}) 1194 | # Get appliance id 1195 | $ApplianceXML = [xml](Get-Content -Path $ApplianceConfig) 1196 | $ApplianceID = $ApplianceXML.ApplianceConfig.ApplianceID 1197 | 1198 | # Prepare Connection 1199 | $BindingURL = ("https://{0}/dms2/services2/ServerEI2?wsdl" -f $ServerName) 1200 | 1201 | ## Add one or more keypairs to the array, depending on method parameter needs. 1202 | $KeyPairs = @() 1203 | $KeyPair = [PSObject]@{Key='applianceID'; Value=$ApplianceID;} 1204 | $KeyPairs += $KeyPair 1205 | 1206 | ## Pre Powershell 7 : Method using WebserviceProxy 1207 | #$Connection = New-Webserviceproxy $BindingURL 1208 | 1209 | # Get data from N-Central. Old and New line for comparison and easy conversion of existing scripts. 1210 | #$rc = $Connection.deviceGet($UserName, $Password, $KeyPairs) 1211 | $rc = GetNCData 'deviceGet' $UserName $Password $KeyPairs 1212 | 1213 | # Extract the Customer-ID and display. 1214 | $CustomerID = ($rc.info | where-object {$_.key -eq "device.customerid"}).value 1215 | $CustomerID 1216 | ``` 1217 | 1218 | 1219 | 1220 | 1221 | 1222 | # Credits 1223 | Special Thanks go to the following Partners and Community Members for their contributions to the **NC-API-Documentation** 1224 | * David Brooks of Premier Technology Solutions 1225 | * Adriaan Sluis of Tosch for PS-NCentral and notes 1226 | * Joshua Bennet of Impact Networking for notes on EiKeyValue usage 1227 | -------------------------------------------------------------------------------- /GetCDPFromAPI: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | @" 4 | CDPFromAPI.ps1 5 | 6 | The script retrieves the Custom Device Properties of all devices 7 | 8 | The API user requires the following role permissions: 9 | Devices->LAN/WAN Devices 10 | * Custom Device Properties - Manage 11 | * LAN/WAN Devices Settings - Manage 12 | 13 | Created by: Jon Czerwinski, Cohn Consulting Corporation 14 | Date: December 3, 2018 15 | Version: 1.0 16 | 17 | "@ 18 | 19 | # 20 | # Generate a pseudo-unique namespace to use with the New-WebServiceProxy and 21 | # associated types. 22 | # 23 | # By controlling the namespace, the script becomes portable and is not 24 | # dependent upon the endpoint url the webservice is connecting. However, this 25 | # introduces another complexity because once the namespace is defined within a 26 | # powershell session, it cannot be reused, nor can it be undefined. As long as 27 | # all the calls are made to the existing webserviceproxy, then everything would be 28 | # OK. But, if you try to rerun the script without closing and reopening the 29 | # powershell session, you will get an error. 30 | # 31 | # One way around this is to create a unique namespace each time the script is run. 32 | # We do this by using the last 'word' of a GUID appended to our base namespace 'NAble'. 33 | # This means our type names for parameters (such as T_KeyPair) now have a dynamic 34 | # type. We could pass types to each new-object call using "$NWSNameSpace.T_KeyPair", 35 | # and I find it more readable to define our 'dynamic' types here and use the typenames 36 | # in variables when calling New-Object. 37 | # 38 | $NWSNameSpace = "NAble" + ([guid]::NewGuid()).ToString().Substring(25) 39 | $KeyPairType = "$NWSNameSpace.T_KeyPair" 40 | $DevicePropertyType = "$NWSNameSpace.DeviceProperty" 41 | $DevicePropertiesType = "$NWSNameSpace.DeviceProperties" 42 | 43 | Write-Output "Using Namespace $NWSNameSpace" 44 | Write-Output " " 45 | 46 | 47 | # 48 | # Locate the Windows Agent Config folder 49 | # 50 | # By querying the Windows Agent Service path, the folder will be correctly identified 51 | # even if it's not on the C: drive. 52 | # 53 | $AgentConfigFolder = (gwmi win32_service -filter "Name like 'Windows Agent Service'").PathName 54 | $AgentConfigFolder = $AgentConfigFolder.Replace("bin\agent.exe", "config").Replace('"','') 55 | 56 | 57 | # 58 | # Get the N-Central server out of the ServerConfig.xml file 59 | # 60 | function Get-NCentralSvr() { 61 | $ConfigXML = [xml](Get-Content "$Script:AgentConfigFolder\ServerConfig.xml") 62 | $ConfigXML.ServerConfig.ServerIP 63 | } 64 | 65 | 66 | # 67 | # Get the device's ApplianceID out of the ApplianceConfig.xml file 68 | # 69 | function Get-ApplianceID() { 70 | $ConfigXML = [xml](Get-Content "$Script:AgentConfigFolder\ApplianceConfig.xml") 71 | $ConfigXML.ApplianceConfig.ApplianceID 72 | } 73 | 74 | 75 | # 76 | # Determine where the N-Central server is 77 | # 78 | $serverHost = Read-Host "Enter the fqdn of the N-Central Server " 79 | 80 | # 81 | # Get credentials 82 | # We could read them as plain text and then create a SecureString from it 83 | # By reading it as a SecureString, the password is obscured on entry 84 | # 85 | # We still have to extract a plain-text version of the password to pass to 86 | # the API call. 87 | # 88 | $username = Read-Host "Enter N-Central user id " 89 | $secpasswd = Read-Host "Enter password " -AsSecureString 90 | 91 | $creds = New-Object System.Management.Automation.PSCredential ("\$username", $secpasswd) 92 | $password = $creds.GetNetworkCredential().Password 93 | 94 | $bindingURL = "https://" + $serverHost + "/dms/services/ServerEI?wsdl" 95 | $nws = New-Webserviceproxy $bindingURL -credential $creds -Namespace ($NWSNameSpace) 96 | 97 | # 98 | # Set up and execute the query 99 | # 100 | $DevProps = $nws.devicePropertyList( 101 | $username, 102 | $password, 103 | $null, # Pass nulls and get *all devices* 104 | $null, 105 | $null, 106 | $null, 107 | $false 108 | ) 109 | 110 | ($DevProps).Count 111 | Foreach ($Device in $DevProps) { 112 | $Device.Properties | ft * 113 | } 114 | -------------------------------------------------------------------------------- /GetCustomerListwithSites-Prompted.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/N-able/API/7c2fb35a0902ea533e1fa516937f583c06d24fee/GetCustomerListwithSites-Prompted.ps1 -------------------------------------------------------------------------------- /GetDeviceInfor-Prompted.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | @" 4 | GetDeviceInfo-Prompted.ps1 5 | 6 | This script reads the Windows Agent config files to determine 7 | its appliance ID and the fqdn of the N-Central server. It then 8 | prompts the user for credentials and queries the N-Central server 9 | for device information. 10 | 11 | It returns the device's name as displayed in N-Central, the 12 | CustomerID the device is associated with, and the Customer Name. 13 | 14 | Created by: Jon Czerwinski, Cohn Consulting Corporation 15 | Date: November 10, 2013 16 | Version: 1.0 17 | 18 | "@ 19 | 20 | # 21 | # Locate the Windows Agent Config folder 22 | # 23 | # By querying the Windows Agent Service path, the folder will be correctly identified 24 | # even if it's not on the C: drive. 25 | # 26 | $AgentConfigFolder = (gwmi win32_service -filter "Name like 'Windows Agent Service'").PathName 27 | $AgentConfigFolder = $AgentConfigFolder.Replace("bin\agent.exe", "config").Replace('"','') 28 | 29 | 30 | # 31 | # Get the N-Central server out of the ServerConfig.xml file 32 | # 33 | function Get-NCentralSvr() { 34 | $ConfigXML = [xml](Get-Content "$Script:AgentConfigFolder\ServerConfig.xml") 35 | $ConfigXML.ServerConfig.ServerIP 36 | } 37 | 38 | 39 | # 40 | # Get the device's ApplianceID out of the ApplianceConfig.xml file 41 | # 42 | function Get-ApplianceID() { 43 | $ConfigXML = [xml](Get-Content "$Script:AgentConfigFolder\ApplianceConfig.xml") 44 | $ConfigXML.ApplianceConfig.ApplianceID 45 | } 46 | 47 | 48 | # 49 | # Determine who we are and where the N-Central server is 50 | # 51 | $serverHost = Get-NCentralSvr 52 | $applianceID = Get-ApplianceID 53 | 54 | 55 | # 56 | # Get credentials 57 | # We could read them as plain text and then create a SecureString from it 58 | # By reading it as a SecureString, the password is obscured on entry 59 | # 60 | # We still have to extract a plain-text version of the password to pass to 61 | # the API call. 62 | # 63 | $username = Read-Host "Enter N-Central user id" 64 | $secpasswd = Read-Host "Enter password" -AsSecureString 65 | 66 | $creds = New-Object System.Management.Automation.PSCredential ("\$username", $secpasswd) 67 | $password = $creds.GetNetworkCredential().Password 68 | 69 | $bindingURL = "https://" + $serverHost + "/dms/services/ServerEI?wsdl" 70 | $nws = New-Webserviceproxy $bindingURL -credential $creds 71 | 72 | 73 | # 74 | # Feedback entered and discovered parameters 75 | # 76 | Write-Host 77 | Write-Host "I am appliance - $applianceID - and my N-Central server is - $serverHost" 78 | Write-Host "I will connect as $username with password $password" 79 | Write-Host 80 | 81 | 82 | # 83 | # Set up and execute the query 84 | # 85 | $KeyPairs = @() 86 | 87 | $KeyPair = New-Object Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1com_dms_services_ServerEI_wsdl.T_KeyPair 88 | $KeyPair.Key = 'applianceID' 89 | $KeyPair.Value = $applianceID 90 | $KeyPairs += $KeyPair 91 | 92 | $rc = $nws.deviceGet($username, $password, $KeyPairs) 93 | 94 | <# 95 | # 96 | # Dump all device info 97 | # 98 | foreach ($device in $rc) { 99 | foreach ($item in $device.Info) { 100 | Write-Host $item.Key ":" 101 | Write-Host $item.Value 102 | Write-Host 103 | } 104 | } 105 | #> 106 | 107 | 108 | # 109 | # Extract and return 110 | # N-Central device name 111 | # CustomerID 112 | # Customer Name 113 | # 114 | foreach ($device in $rc) { 115 | $DeviceInfo = @{} 116 | 117 | foreach ($item in $device.Info) {$DeviceInfo[$item.key] = $item.Value} 118 | 119 | Write-Host "N-Central Device Name: " $DeviceInfo['device.longname'] 120 | Write-Host "Customer ID: " $DeviceInfo['device.customerid'] 121 | Write-Host "Customer Name: " $DeviceInfo['device.customername'] 122 | Write-Host 123 | 124 | Remove-Variable DeviceInfo 125 | } 126 | -------------------------------------------------------------------------------- /GetFilteredDevicesPrinterInfo-Prompted.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | @" 4 | GetDeviceFilteredPrinterInfo-Prompted.ps1 5 | 6 | This script outputs printer information for all devices matching the given 7 | N-Central filter. The script prompts for five paramters: 8 | 9 | N-Central server name 10 | N-Central userid 11 | N-Central password 12 | N-Central filter 13 | Output CSV filename 14 | 15 | Created by: Jon Czerwinski, Cohn Consulting Corporation 16 | Date: December 16, 2013 17 | Version: 1.0 18 | 19 | "@ 20 | 21 | 22 | # 23 | # Determine where the N-Central server is 24 | # 25 | $serverHost = Read-Host "Enter the fqdn of the N-Central Server " 26 | 27 | 28 | # 29 | # Generate a pseudo-unique namespace to use with the New-WebServiceProxy and 30 | # associated types. 31 | # 32 | # By controlling the namespace, the script becomes portable and is not 33 | # dependent upon the endpoint url the webservice is connecting. However, this 34 | # introduces another complexity because once the namespace is defined within a 35 | # powershell session, it cannot be reused, nor can it be undefined. As long as 36 | # all the calls are made to the existing webserviceproxy, then everything would be 37 | # OK. But, if you try to rerun the script without closing and reopening the 38 | # powershell session, you will get an error. 39 | # 40 | # One way around this is to create a unique namespace each time the script is run. 41 | # We do this by using the last 'word' of a GUID appended to our base namespace 'NAble'. 42 | # This means our type names for parameters (such as T_KeyPair) now have a dynamic 43 | # type. We could pass types to each new-object call using "$NWSNameSpace.T_KeyPair", 44 | # and I find it more readable to define our 'dynamic' types here and use the typenames 45 | # in variables when calling New-Object. 46 | # 47 | $NWSNameSpace = "NAble" + ([guid]::NewGuid()).ToString().Substring(25) 48 | $KeyPairType = "$NWSNameSpace.T_KeyPair" 49 | $KeyValueType = "$NWSNameSpace.T_KeyValue" 50 | 51 | 52 | # 53 | # Create PrinterData type to hold printer name and port 54 | # 55 | Add-Type -TypeDefinition @" 56 | public class PrinterData { 57 | public string CustomerName; 58 | public string ComputerName; 59 | public string PrinterName; 60 | public string PrinterPort; 61 | } 62 | "@ 63 | 64 | 65 | # 66 | # Get credentials 67 | # We could read them as plain text and then create a SecureString from it 68 | # By reading it as a SecureString, the password is obscured on entry 69 | # 70 | # We still have to extract a plain-text version of the password to pass to 71 | # the API call. 72 | # 73 | $username = Read-Host "Enter N-Central user id " 74 | $secpasswd = Read-Host "Enter password " -AsSecureString 75 | 76 | $creds = New-Object System.Management.Automation.PSCredential ("\$username", $secpasswd) 77 | $password = $creds.GetNetworkCredential().Password 78 | 79 | $bindingURL = "https://" + $serverHost + "/dms/services/ServerEI?wsdl" 80 | $nws = New-Webserviceproxy $bindingURL -credential $creds -Namespace ($NWSNameSpace) 81 | 82 | 83 | # 84 | # Get the filter name to use 85 | # 86 | Write-Host 87 | $FilterName = (Read-Host "Enter the exact filter name ").Trim() 88 | 89 | 90 | # 91 | # Select the output file 92 | # 93 | Write-Host 94 | $CSVFile = (Read-Host "Enter the CSV output filename ").Trim() 95 | 96 | 97 | # 98 | # Set up and execute the query 99 | # 100 | $KeyPairs = @() 101 | 102 | $KeyPair = New-Object -TypeName $KeyValueType 103 | $KeyPair.Key = 'TargetByFilterName' 104 | $KeyPair.Value = $FilterName 105 | $KeyPairs += $KeyPair 106 | 107 | $KeyPair = New-Object -TypeName $KeyValueType 108 | $KeyPair.Key = 'InformationCategoriesInclusion' 109 | $KeyPair.Value = @("asset.customer", "asset.device", "asset.printer") 110 | $KeyPairs += $KeyPair 111 | 112 | $rc = $nws.DeviceAssetInfoExport2("0.0", $username, $password, $KeyPairs) 113 | 114 | 115 | # 116 | # Set up the printers array, then populate with the printer name and port 117 | # 118 | $Printers = @() 119 | 120 | foreach ($device in $rc) { 121 | $DeviceAssetInfo = @{} 122 | foreach ($item in $device.Info) {$DeviceAssetInfo[$item.key] = $item.Value} 123 | 124 | $CustomerName = $DeviceAssetInfo['asset.customer.customername'] 125 | $ComputerName = $DeviceAssetInfo['asset.device.longname'] 126 | $index = 0 127 | 128 | While ($DeviceAssetInfo["asset.printer.name.$index"]) { 129 | $Printer = New-Object PrinterData 130 | $Printer.CustomerName = $CustomerName 131 | $Printer.ComputerName = $ComputerName 132 | $Printer.PrinterName = $DeviceAssetInfo["asset.printer.name.$index"] 133 | $Printer.PrinterPort = $DeviceAssetInfo["asset.printer.port.$index"] 134 | 135 | $Script:Printers += $Printer 136 | $index ++ 137 | } 138 | 139 | If ($index -gt 0) { 140 | Write-Host "Found $index printers on $CustomerName - $ComputerName" 141 | } 142 | 143 | Remove-Variable DeviceAssetInfo 144 | } 145 | 146 | $Printers | Export-Csv -Path $CSVFile -NoTypeInformation -Force 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # API 2 | ## Contents 3 | | Type | Name | API Version | Contents | 4 | | --- | -----| -----|-------- | 5 | | Folder | **APIv2** | v2 | Contains documentation and scripting examples for version 2 of the N-Central API in 2020.x, covering creating connections, queries, updating values, adding customers with native web proxy services and the PS-Ncentral powershell module by Tosch | 6 | | File | GetCDPFromAPI | v1 |The script retrieves the Custom Device Properties of all devices | 7 | | File | GetCustomerListwithSites-Prompted.ps1 | v1 | This script outputs the customer list | 8 | | File | GetDeviceInfor-Prompted.ps1 | v1 | Reads Windows Agent config for the appliance ID and the fqdn of the N-Central server. Prompts the user for credentials and queries the N-Central server for device information. | 9 | |File | GetFilteredDevicesPrinterInfo-Prompted.ps1 | v1 | This script outputs printer information for all devices matching the given N-Central filter | 10 | 11 | --------------------------------------------------------------------------------