search
Categories
Sponsors
VirtualMetric Hyper-V Monitoring, Hyper-V Reporting
Archive
Blogroll

Badges
MCSE
Community

Cozumpark Bilisim Portali
Kayako Classic to Freshdesk Migration via PowerShell
Posted in Windows Powershell | No Comment | 1,030 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)

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!"))

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
}

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
}

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
}

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
}

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
}

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++
		}
	}
}

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

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.



Leave a Reply