Replace IP by DNS Name
Hello,
I got from Eric and Josh a script which is having the basic code to do the task I need. I would like to replace the IP Address/DNS Name by the DNS Name for all our servers.
<span class="pln">######################### API Function Script #########################
#------------------------------------------------------------------------------------------------------------
# Prerequisites:
#
# Requires -Version 3
#------------------------------------------------------------------------------------------------------------
# Initialize Variables
<# account info #>
$accessId = "1234567890-"
$accessKey = '1234567890-'
$company = "xxxxxxxx"
#------------------------------------------------------------------------------------------------------------
# Functionize the reusable code that builds and executes the query
function Send-Request() {
Param(
[Parameter(position = 0, Mandatory = $true)]
[string]$path,
[Parameter(position = 1, Mandatory = $false)]
[string]$httpVerb = 'GET',
[Parameter(position = 2, Mandatory = $false)]
[string]$queryParams,
[Parameter(position = 3, Mandatory = $false)]
[PSObject]$data
)
# Use TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
<# Construct URL #>
$url = "https://$company.logicmonitor.com/santaba/rest$path$queryParams"
<# Get current time in milliseconds #>
$epoch = [Math]::Round((New-TimeSpan -start (Get-Date -Date "1/1/1970") -end (Get-Date).ToUniversalTime()).TotalMilliseconds)
<# Concatenate Request Details #>
$requestVars = $httpVerb + $epoch + $data + $path
<# Construct Signature #>
$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.Key = [Text.Encoding]::UTF8.GetBytes($accessKey)
$signatureBytes = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($requestVars))
$signatureHex = [System.BitConverter]::ToString($signatureBytes) -replace '-'
$signature = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($signatureHex.ToLower()))
<# Construct Headers #>
$auth = 'LMv1 ' + $accessId + ':' + $signature + ':' + $epoch
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", $auth)
$headers.Add("Content-Type", 'application/json')
$headers.Add("X-version", '2')
<# Make request & retry if failed due to rate limiting #>
$Stoploop = $false
do {
try {
<# Make Request #>
$response = Invoke-RestMethod -Uri $url -Method $httpVerb -Body $data -Header $headers
$Stoploop = $true
} catch {
switch ($_) {
{ $_.Exception.Response.StatusCode.value__ -eq 429 } {
Write-Host "Request exceeded rate limit, retrying in 60 seconds..."
Start-Sleep -Seconds 60
$response = Invoke-RestMethod -Uri $url -Method $httpVerb -Body $data -Header $headers
}
{ $_.Exception.Response.StatusCode.value__ } {
Write-Host "Request failed, not as a result of rate limiting"
# Dig into the exception to get the Response details.
# Note that value__ is not a typo.
Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
Write-Host "StatusDescription:" $_.Exception.Response.StatusCode
$_.ErrorDetails.Message -match '{"errorMessage":"([\d\S\s]+)","errorCode":(\d+),'
Write-Host "LM ErrorMessage" $matches[1]
Write-Host "LM ErrorCode" $matches[2]
$response = $null
$Stoploop = $true
}
default {
Write-Host "An Unknown Exception occurred:"
Write-Host $_ | Format-List -Force
$response = $null
$Stoploop = $true
}
}
}
} While ($Stoploop -eq $false)
Return $response
}
# Get list of Resources
$members = {VRPSCCMRS01}
$httpVerb = 'GET'
$resourcePath = "/device/devices/$member.id"
$queryParams = $null
$data = $null
$results = Send-Request $resourcePath $httpVerb $queryParams $data
foreach ($hostname in $results.items) {
$sysname = (($hostname.systemProperties) | Where-Object -Property "Name" -eq "system.sysname").value
if ($sysname -match "\.") {
$newName = $sysname.split(".")[0]
} else {
$newName = $sysname
}
if ($hostname.Name -eq $newName) {
Write-Host "Name `"$($hostname.displayName)`" matched no change needed"
} else {
$httpVerb = 'PATCH'
$resourcePath = "/device/devices/$($deviceId)"
$queryParams = "?patchFields=Name&opType=replace"
$data = @{
Name = $newName
} | ConvertTo-Json
Send-Request $resourcePath $httpVerb $queryParams $data
Write-Host "Changed host id $($hostname.id) Name from `"$($hostname.ips)`" to `"$newName`"."
}
}</span>but for now I am getting an error:
<span class="pln">Request failed, not as a result of rate limiting
StatusCode: 404
StatusDescription: NotFound
LM ErrorMessage HTTP 404 Not Found
LM ErrorCode 1400</span>Any idea of the issue?
Test in progress
Thanks,
Dom

Dominique
Posted 6 years ago·Last reply 6 years ago
41 comments
Dominique
OP6 years agoHello Stuart,
As promised this is the script which is set in the Property Source
Thanks,
Dominique
LM User
·6 years agoPlease check your direct messages here in the communities. Let's figure it out privately then post the working script back here for others to benefit from.
Dominique
OP6 years agoIt is the displayname which has been updated from VRPSCCMRS01 to $currentName!!! not the IP Address/DNSName...
I updated DisplayName manually back to VRPSCCMRS01...
Thanks,
Dom
Dominique
OP6 years agoTrying to run the "Test Script" on the PropertySource there is an error:
It does not get the server name but the variable name !!! strange!!!
Still checking...
Thanks,
Dom
Dominique
OP6 years agoI am getting again an invalid output format!!!
Not sure which account should be used? which accessID? which accessKey?
Dominique
OP6 years agoOne account is in AD and one account is local dixit our LM Administrators team...
So the AccessID should be rx65 ... I will give a try now
Dominique
OP6 years agoI noticed I have two accounts:
my account id with a key rz65...
my email id with a key qaE6...
what are the differences? which one is used to access the devices?
Thanks,
Dom
Dominique
OP6 years agoI changed the accessid... to qaE6...
Still no change in the IP Address/DNS Name...
LM User
·6 years agoTaking this conversation private.
Dominique
OP6 years agoI am using 9e266 which is on the device...
I check on my User account the ID ,
Thanks,
Dom
LM User
·6 years agoLooks like the token id and key you are trying to use doesn't match an existing token id/key. 9e266... is the one you're trying to use, but that API token doesn't exist. Perhaps update the device properties to the qaE65...id and key?
Dominique
OP6 years agoI commented all Write-Host statements in the function...
but still no update !!
Thanks,
Dom
LM User
·6 years agoYeah, you have some Write-Host statements in the function that are being output along with the final output. The only output should be the actual property with its value.
Instead of doing the Write-Host statements, you could maintain an "output" variable with all the debug messaging and then at the end output that in your final if/else statement.
Dominique
OP6 years agoAdded the Function SendRequest but getting an Error ...
Dominique
OP6 years agoYes ip2dns.result is on the device.
LM User
·6 years agoAny properties written using "Write-Host" will not be saved to the device, but the patch operation would be attempted. However, you're missing the Send-Request function definition, so nothing's being done.
LM User
·6 years agoHey, looking good. You should see the ip2dns.result property on the device now.
It looks like you're trying to call the Send-Request function without actually having that function defined. It might be as simple as copying the Send-Request function from the script you were given. If that function is written properly, it should work.
Dominique
OP6 years agothis is the current script, I think I am missing something ...
BTW when doing "test script" in the PropertySource does it write the machine used during the test?
Thanks,
Dom
Dominique
OP6 years agoChanged IP 10.6.195.211 to DNS VRPSCCMRS01
No error during execution, the message at the end is successful but the change did not happened.
Reviewing the script...
Thanks,
Dom
Dominique
OP6 years agoI created the PropertySource "_Replace_IP_Address_by_DNSName"
Testing now...
Thanks,
Dom
Dominique
OP6 years agoLet me try to do a PropertySource as we never know what will happen :)/emoticons/smile@2x.png 2x" title=":)" width="20">
LM User
·6 years agoI think I was misunderstanding because I was going the route of running it continually, not once and done.
If you're just running it once, I think you're making it more difficult. By running it as a propertysource, you don't have to do one API GET to grab the displayName and name, you can grab those via tokens. Then all you have to do is a single patch for those devices that don't match. By running it on your laptop, you have to do multiple API calls to get the details about what you want to compare, then another API call to make the change. Not only that, but by making it a PropertySource, you can easily limit it to just the one device without having to change your code.
For security reasons, if you're running it on your laptop, at least set the API key as an environment variable so that you don't accidentally post the token and key again to this publicly available forum.
Dominique
OP6 years agoYou understood perfectly the target it is to run it "usually" once to correct all IPs imported in the IP Address/DNS Name field by the DNS Name only
If they will be more later on except the scale is large it will be done manually...
Thanks,
Dom
LM User
·6 years agoOk, perhaps I'm misunderstanding your goal. Do you want this to happen on an ongoing basis, or do you want something you can run once and be done, or run once every month? By writing a PropertySource, you'll see it work much simpler (see above code) and it'll run continuously so all devices will be in the proper state.
LM User
·6 years agoI went and disabled that API token. You should delete it and generate a new one.
I created two properties on VRPSCCMRS01: ip2dns.accessid and ip2dns.key, containing a new API token id and key. Your script should use ##IP2DNS.ACCESSID## ##IP2DNS.KEY## to pull those values into the script at runtime.
Your script should take on a form something like this:
I'm not a Powershell guy, so while I can follow what your script is trying to do, I can't really help you write the function to do it.
Dominique
OP6 years agoHello,
The script is running from my Laptop using an "Administrator: Windows Powershell ISE" prompt as recommended:
"Once modified, this script can run from any computer. Please take caution when doing large scale modification like this as this is a production system and mistake/bugs can be difficult to revert. Below is a screenshot of a demo Postman request showing the payload format."
I was looking to limit thescale by using the device ID 128... only
No PropertySource was built...
Thanks,
Dom
LM User
·6 years agoPerhaps we are getting to the root of the problem. How are you running this script? If you're not running it using "Test Script" in the LM GUI, then it won't work. You will have to build some sort of LogicModule to run this code. My suggestion is that it be a PropertySource. They run regularly and can store the output of the execution as a property that you can use for grouping/reporting to identify which ones are getting renamed.
Have you started building a PropertySource? This would also let you not embed your api key and token in your script. I'll go back and edit your posts to remove them, but I suggest destroying that token and generating a new one. Like, you should do that right now. Like, right now.
Dominique
OP6 years agoHello,
is giving an error:
Request failed, not as a result of rate limiting
StatusCode: 401
StatusDescription: Unauthorized
LM ErrorMessage HTTP 401 Unauthorized
LM ErrorCode 1400
Thanks,
Dom
Dominique
OP6 years agoI tried this before but I think it was erroring let me try it again..
Thanks,
Dom
Dominique
OP6 years agoHello,
Not sure what you are looking for:
the URL is https://uclahealth.logicmonitor.com/santaba/uiv3/device/index.jsp#tree/-5-d-128
These are the information from the Info tab on the resource:
The system.devideId is 128
The system.displayname is VRPSCCMRS01
Thanks,
Dom
LM User
·6 years agoNo, I need the name of the PropertySource (LogicModule) where this code lives.
LM User
·6 years agoThis is the URL that should be used, however, it has to be in the proper format. So, let's look at $path and $queryParams to make sure they contain what they should so that the path is a properly formed URI.
$path would need to start with a forward slash (/). $queryParams would need to start with a question mark and be a list of ampersand separated key value pairs (e.g. ?size=1&page=3). It looks like both of those are good, but commented out currently.
FYI, you can't change the display name if you're doing a GET. You'll have to do PATCH. More info here. It would be something like this:
Dominique
OP6 years agoHello,
This is to access the machine VRPSCCMRS01 for the testing of the script to limit it to one machine at the beginning, not impacting all machines...
The Property is system.deviceId.
Thanks,
Dom
LM User
·6 years agoThis wouldn't work because it's not calling the API. What's the name of the propertysource? I can take a look on the back end to see what's up.
Dominique
OP6 years agoReplacing
$resourcePath = '/device/devices/128'
by $resourcePath = 'https://uclahealth.logicmonitor.com/santaba/uiv3/device/index.jsp#tree/-5-d-128'...
No error either but still no update it seems that the loop : "foreach $hostname in $results.items" never starts...
it looks like the:
$results = Send-Request $resourcePath $httpVerb $queryParams $data
does not contain the correct information???? not sure what the Get should be followed by...
Get 'https://uclahealth.logicmonitor.com/santaba/uiv3/device/index.jsp#tree/-5-d-128' 'Name' 'Name'
Thanks,
Dom
Dominique
OP6 years agoHello,
With this script
there is no more error but it is not changing the IPs to DNS names...
Thanks,
Dom
LM User
·6 years agoJust getting back from vacation, so let me know if what questions are still pending.
I assume you will be running this script as a propertysource? If so, then all you need to do is set the AppliesTo either to that one device or to that one group. You can use the AppliesTo wizard to help set that.
Instead of just writing the result to screen, I'd write it out as a property so that each device that has been changed will have a message in a custom property (ip2dns.renamed for example) detailing the result of the run.
You don't need to do an API call to get the device ID nor to get the address/name. Use tokens. You can simply set a variable (e.g. $hostname) to ##HOSTNAME##. When the collector runs the posh, it will replace those tokens where available. So, ##SYSTEM.HOSTNAME## would be replaced with the 10.6.195.211 and ##SYSTEM.DISPLAYNAME## would get replaced with VRPSCCMRS01. You can get the device id as well, using ##SYSTEM.DEVICEID##.
You can also store the script credentials as properties, so they're not hard coded into the script. So it would become something like this:
I like to have a specific API token for each LogicModule that uses the API. It makes it really easy to track down the cause of a problem when something goes awry.
I would say that definitely looks like an authentication failure.
Dominique
OP6 years agoHello,
If I believe the documentation https://www.logicmonitor.com/support/rest-api-developers-guide/v2 this is an authentication failure
Does this mean this is the part:
# Initialize Variables
<# account info #>
$accessId = "xxxxxxxxxxxxxxx"
$accessKey = 'yyyyyyyyyyyyyyyyyyyyyyyyyyyy'
$company = "123456"
Which is incorrect?
Or is it something else?
Thanks,
Dom
Dominique
OP6 years agoHello,
I am trying
$resourcePath = "/device/devices/128"
considering the system.deviceid of VRPSCCMRS01 is 128
but the script does not give anything ... no message that it failed, no message that the replacement was successfully done!
Thanks,
Dom
Dominique
OP6 years agoHello,
My questions are:
How will i limit this script to run on the device VRPSCCMRS01?
How will i limit this script to run on the group IT Ops Systems Management Group > Production > SCCM Servers?
Thanks,
Dom
Dominique
OP6 years agoI have added:
As I would like to test the script on only one machine VRPSCCMRS01
Thanks,
Dom