Posted in
Windows Powershell |
No Comment | 1,026 views | 26/10/2017 13:40
If you need to migrate from Kayako Classic to Freshdesk, you may use following script.
This is just an example script that i wrote in a few minutes.
First create connection to Kayako Classic via API information:
Add-Type -AssemblyName System.Web
$apiKey = "e5b3990a-5c6f-6634-2db3-6ff3f5d5036d";
$secretKey = "ZTBmNTIyNTItZTRhZC00ZDQ0LTY1MTktN2Q5MTFlYTUyNDdmNWZiOTRiNDQtZTNhZC0zOTE0LTBkZmQtMGZkMDY4YTRmMmY1";
$salt = [guid]::NewGuid().ToString();
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secretKey)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($salt))
$signature = [Convert]::ToBase64String($signature)
$encodedSignature = [System.Web.HttpUtility]::UrlEncode($signature) |
Add-Type -AssemblyName System.Web
$apiKey = "e5b3990a-5c6f-6634-2db3-6ff3f5d5036d";
$secretKey = "ZTBmNTIyNTItZTRhZC00ZDQ0LTY1MTktN2Q5MTFlYTUyNDdmNWZiOTRiNDQtZTNhZC0zOTE0LTBkZmQtMGZkMDY4YTRmMmY1";
$salt = [guid]::NewGuid().ToString();
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secretKey)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($salt))
$signature = [Convert]::ToBase64String($signature)
$encodedSignature = [System.Web.HttpUtility]::UrlEncode($signature)
Then get prepare for Freshdesk connection. Type your Freshdesk username and password:
$AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
$userpassB64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("test@domain.com:myPassword!")) |
$AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
$userpassB64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("test@domain.com:myPassword!"))
User Migration:
$userLink = "http://domain.kayako.com/api/Base/User/Filter&apikey=$apiKey&salt=$salt&signature=$signature"
[xml]$xml = (Invoke-WebRequest $userLink).Content
foreach ($topic in $xml.users.user) {
$contactJson = @{
name = $topic.fullname.InnerText
email = $topic.email.InnerText
}| ConvertTo-Json -Compress
Invoke-WebRequest -Headers @{Authorization = "Basic $userpassB64"} `
-Uri https://domain.freshdesk.com/api/v2/contacts `
-ContentType "application/json" -Method Post -Body $contactJson
} |
$userLink = "http://domain.kayako.com/api/Base/User/Filter&apikey=$apiKey&salt=$salt&signature=$signature"
[xml]$xml = (Invoke-WebRequest $userLink).Content
foreach ($topic in $xml.users.user) {
$contactJson = @{
name = $topic.fullname.InnerText
email = $topic.email.InnerText
}| ConvertTo-Json -Compress
Invoke-WebRequest -Headers @{Authorization = "Basic $userpassB64"} `
-Uri https://domain.freshdesk.com/api/v2/contacts `
-ContentType "application/json" -Method Post -Body $contactJson
}
Getting departments from Kayako:
$departmentLink = "http://domain.kayako.com/api/ `
Base/Department&apikey=$apiKey&salt=$salt&signature=$signature"
[xml]$xml = (Invoke-WebRequest $departmentLink).Content
foreach ($topic in $xml.departments.department) {
write-host ID: $topic.id
write-host Title: $topic.title.InnerText
write-Host Type: $topic.type.InnerText
} |
$departmentLink = "http://domain.kayako.com/api/ `
Base/Department&apikey=$apiKey&salt=$salt&signature=$signature"
[xml]$xml = (Invoke-WebRequest $departmentLink).Content
foreach ($topic in $xml.departments.department) {
write-host ID: $topic.id
write-host Title: $topic.title.InnerText
write-Host Type: $topic.type.InnerText
}
Getting tickets from Kayako:
$departmentId = 1
$ticketLink = "http://domain.kayako.com/api/Tickets/Ticket/ListAll/$departmentId/ `
1,2,3,4,5,6,7,8,9&apikey=$apiKey&salt=$salt&signature=$encodedSignature"
[xml]$xml = (Invoke-WebRequest $ticketLink).Content
foreach ($topic in $xml.tickets.ticket) {
write-host ID: $topic.id
write-host Subject: $topic.subject.InnerText
write-host FullName: $topic.fullname.InnerText
write-host Email: $topic.email.InnerText
write-host Replies: $topic.replies.InnerText
} |
$departmentId = 1
$ticketLink = "http://domain.kayako.com/api/Tickets/Ticket/ListAll/$departmentId/ `
1,2,3,4,5,6,7,8,9&apikey=$apiKey&salt=$salt&signature=$encodedSignature"
[xml]$xml = (Invoke-WebRequest $ticketLink).Content
foreach ($topic in $xml.tickets.ticket) {
write-host ID: $topic.id
write-host Subject: $topic.subject.InnerText
write-host FullName: $topic.fullname.InnerText
write-host Email: $topic.email.InnerText
write-host Replies: $topic.replies.InnerText
}
Getting ticket posts from Kayako:
$ticketId = 518
$ticketPostLink = "http://domain.kayako.com/api/Tickets/TicketPost/ListAll/$ticketId `
&apikey=$apiKey&salt=$salt&signature=$encodedSignature"
[xml]$xml = (Invoke-WebRequest $ticketPostLink).Content
foreach ($topic in $xml.posts.post) {
write-host ID: $topic.id.InnerText
write-host FullName: $topic.fullname.InnerText
write-host Contents: $topic.contents.InnerText
write-host Email: $topic.email.InnerText
} |
$ticketId = 518
$ticketPostLink = "http://domain.kayako.com/api/Tickets/TicketPost/ListAll/$ticketId `
&apikey=$apiKey&salt=$salt&signature=$encodedSignature"
[xml]$xml = (Invoke-WebRequest $ticketPostLink).Content
foreach ($topic in $xml.posts.post) {
write-host ID: $topic.id.InnerText
write-host FullName: $topic.fullname.InnerText
write-host Contents: $topic.contents.InnerText
write-host Email: $topic.email.InnerText
}
Getting ticket notes from Kayako:
$ticketId = 518
$noteLink = "http://domain.kayako.com/api/Tickets/TicketNote/ListAll/$ticketId `
&apikey=$apiKey&salt=$salt&signature=$encodedSignature"
[xml]$xml = (Invoke-WebRequest $noteLink).Content
foreach ($topic in $xml.notes.note) {
write-host ID: $topic.id
} |
$ticketId = 518
$noteLink = "http://domain.kayako.com/api/Tickets/TicketNote/ListAll/$ticketId `
&apikey=$apiKey&salt=$salt&signature=$encodedSignature"
[xml]$xml = (Invoke-WebRequest $noteLink).Content
foreach ($topic in $xml.notes.note) {
write-host ID: $topic.id
}
Migrating tickets from Kayako to Freshdesk:
$departmentId = 1
$ticketLink = "http://domain.kayako.com/api/Tickets/Ticket/ListAll/$departmentId/ `
1,2,3,4,5,6,7,8,9&apikey=$apiKey&salt=$salt&signature=$encodedSignature"
[xml]$xml = (Invoke-WebRequest $ticketLink).Content
foreach ($topic in $xml.tickets.ticket) {
$topicId = $topic.id
$replyCount = 1;
$ticketId = 0;
$ticketPostLink = "http://domain.freshdesk.com/api/Tickets/TicketPost/ListAll/$topicId `
&apikey=$apiKey&salt=$salt&signature=$encodedSignature"
[xml]$postXml = (Invoke-WebRequest $ticketPostLink).Content
$postIds = $postXml.posts.post.id.InnerText | Sort-Object
foreach ($postId in $postIds)
{
$post = $postXml.posts.post | where {$_.id.InnerText -eq $postId}
if ($replyCount -eq 1)
{
$ticketJson = @{
description = $post.contents.InnerText
subject = $topic.subject.InnerText
email = $post.email.InnerText
priority = 1
status = 5
}| ConvertTo-Json -Compress
$ticketPost = Invoke-WebRequest -Headers @{Authorization = "Basic $userpassB64"} `
-Uri https://domain.freshdesk.com/api/v2/tickets `
-ContentType "application/json" -Method Post -Body $ticketJson
$ticketPostJson = $ticketPost.Content | ConvertFrom-Json
$ticketId = $ticketPostJson.id
$replyCount++
}
else
{
$ticketNoteJson = @{
body = $post.contents.InnerText
private = $false
}| ConvertTo-Json -Compress
Invoke-WebRequest -Headers @{Authorization = "Basic $userpassB64"} `
-Uri https://domain.freshdesk.com/api/v2/tickets/$ticketId/notes `
-ContentType "application/json" -Method Post -Body $ticketNoteJson
$replyCount++
}
}
} |
$departmentId = 1
$ticketLink = "http://domain.kayako.com/api/Tickets/Ticket/ListAll/$departmentId/ `
1,2,3,4,5,6,7,8,9&apikey=$apiKey&salt=$salt&signature=$encodedSignature"
[xml]$xml = (Invoke-WebRequest $ticketLink).Content
foreach ($topic in $xml.tickets.ticket) {
$topicId = $topic.id
$replyCount = 1;
$ticketId = 0;
$ticketPostLink = "http://domain.freshdesk.com/api/Tickets/TicketPost/ListAll/$topicId `
&apikey=$apiKey&salt=$salt&signature=$encodedSignature"
[xml]$postXml = (Invoke-WebRequest $ticketPostLink).Content
$postIds = $postXml.posts.post.id.InnerText | Sort-Object
foreach ($postId in $postIds)
{
$post = $postXml.posts.post | where {$_.id.InnerText -eq $postId}
if ($replyCount -eq 1)
{
$ticketJson = @{
description = $post.contents.InnerText
subject = $topic.subject.InnerText
email = $post.email.InnerText
priority = 1
status = 5
}| ConvertTo-Json -Compress
$ticketPost = Invoke-WebRequest -Headers @{Authorization = "Basic $userpassB64"} `
-Uri https://domain.freshdesk.com/api/v2/tickets `
-ContentType "application/json" -Method Post -Body $ticketJson
$ticketPostJson = $ticketPost.Content | ConvertFrom-Json
$ticketId = $ticketPostJson.id
$replyCount++
}
else
{
$ticketNoteJson = @{
body = $post.contents.InnerText
private = $false
}| ConvertTo-Json -Compress
Invoke-WebRequest -Headers @{Authorization = "Basic $userpassB64"} `
-Uri https://domain.freshdesk.com/api/v2/tickets/$ticketId/notes `
-ContentType "application/json" -Method Post -Body $ticketNoteJson
$replyCount++
}
}
}
First of all, be aware of “status = 5”. I migrated all tickets in “closed” state. But if you have many open tickets in Kayako, you may set it as parameter so you can set them open/closed etc.
You might see that I added the old ticket replies as “public note” into Freshdesk. Reason of this, because Freshdesk API supports “TicketReply” method (this is a new method that they made it in 5 years i guess, according to their forum) but simply you can not say that, “do not send notification to customer”. So only way to do this is using “public note” method. In that case you can disable customer notifications.
To be honest, there are many lack of features in Freshdesk and i mean the core features, in API and in the software itself. Or these guys are really terrible at API side, or they just don’t give any effort to backend API. This was one of the most premature API i was dealing with after years, and this is in almost 2018 :)
If you need to see “TicketReply” method, here it is:
$ticketId = 25
$ticketReplyJson = @{
body = "Details about the issue"
}| ConvertTo-Json -Compress
Invoke-WebRequest -Headers @{Authorization = "Basic $userpassB64"} `
-Uri https://domain.freshdesk.com/api/v2/tickets/$ticketId/reply `
-ContentType "application/json" -Method Post -Body $ticketReplyJson |
$ticketId = 25
$ticketReplyJson = @{
body = "Details about the issue"
}| ConvertTo-Json -Compress
Invoke-WebRequest -Headers @{Authorization = "Basic $userpassB64"} `
-Uri https://domain.freshdesk.com/api/v2/tickets/$ticketId/reply `
-ContentType "application/json" -Method Post -Body $ticketReplyJson
But be aware, this will send notification to customer because there is no option to disable notifications.
I hope this would a good guidance for you. This is very simple script meet with my requirements. Please test it before migrating real data.