API Curl to Powershell Device group movement

Solved
D
Douglas
FGL Sports Ltd
I made a few changes, but now getting a (401) Unauthorized error, not sure what else I'm missing.

The Curl API command for moving device groups:
curl -X PUT --header "Content-Type: application/json" --header "Accept: application/json" --header "Authorization: Bearer Very long token" -d "\"\\\\RootFolder\\New folder\"" "https://SOTIServer.com:443/MobiControl/api/devicegroups/%255C%255CRootfolder%255COld%2520folder%255CSourceFolder/path"

The Powershell call that I have so far, that doesn't work:

$folderX="SourceFolder"

function MoveDir ([string]$Name, [string]$Token)
{

$Path = "%255C%255CRootfolder%255COld%2520folder%255C" + $folderX
$body = @{}
$body = "`"\\RootFolder\New Folder`""
$body = $body | ConvertTo-Json

$Header2 = @{}
$Header2["Authorization"] = "Bearer " + $Token

try
{
$response2 = Invoke-restmethod -Uri https://$MCFQDN/mobicontrol/api/devicegroups/$Path/path -ContentType "application/json" -Method PUT -Body $body -Headers $Header2
}
catch
{
$($_.Exception.Message)
}
}

Edited 7 years ago
SOTI MobiControl
ANSWERS
TB
TJ Bukoski
7 years ago

Your script looks good, but I don't know about the input from the file.

Have you tested the script by hard coding a value in the call to your Function?

I may have to take your code and reproduce the issue on my machine.

Solution
SS
Support Staff Account
7 years ago (edited 7 years ago)

Hello Douglas, 

I have reached out to one of our best resources for this type of request to get you an answer, if you have not been able to get one as of yet.

Regards,

D
Douglas
7 years ago

I have not, thank you for forwarding!

TB
TJ Bukoski
7 years ago

The body is wrong but I'm not sure how. So the best advice I can offer is to simplify the code.

instead of:

$Path = "%255C%255CRootfolder%255COld%2520folder%255C" + $folderX

We can have Powershell double encode the path for us:

$Path = "\\RootFolder\OldFolder"

$folderX = "SourceFolder"

$fullpath = $path + $folderx
$fullpath = [uri]::EscapeDataString("$fullpath")
$fullpath = [uri]::EscapeDataString("$fullpath")

And because we only need one line in the body, we don't need to make a Hash table.

$body = @{}
$body = "`"\\RootFolder\New Folder`""
$body = $body | ConvertTo-Json

Becomes

 $body = "\\Rootfolder\New Folder" 
$body = $body | ConvertTo-Json

I don't think you need quotation marks in the path that you put in the body. If I were to guess where the failure is, it's probably that.

D
Douglas
7 years ago

Still giving the same "(401)Unauthorized" error.

I think it has something to do with the missing "Accept" command, how would I add that to the call?

curl -X PUT --header "Content-Type: application/json" --header "Accept: application/json" --header "Authorization: Bearer

TB
TJ Bukoski
7 years ago

That's done by Powershell's Invoke-RestMethod cmdlet with the ContentType Parameter.

Post your script again so I can see what changes you made.

D
Douglas
7 years ago (edited 7 years ago)

Updated with correct code.


$MCUsername = "name"
$MCPassword = "pass"
$MCFQDN = "server.domain.com:443"
$ClientID = "clientid"
$ClientSecret = "clientsecret"


$IDSecret = $ClientID + ":" + $ClientSecret
$EncodedIDSecret = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($IDSecret))

$Body = @{}
$Body["grant_type"]="password"
$Body["username"]=$MCUsername
$Body["password"]=$MCPassword

$Header = @{}
$Header["Authorization"] = "Basic " + $EncodedIDSecret

try
{
   $response = Invoke-restmethod -Uri https://$MCFQDN/mobicontrol/api/token -Method POST -Headers $Header -Body $Body
}
catch
{
   $($_.Exception.Message)
}

$Token = $response.access_token

Write-Host "My MobiControl API Token is: $Token"


$txtFile="E:\Powershell Scripts\test.txt"; # File with list of folder-names to be moved
$pattern="\d+";


function MoveDir ([string]$Store, [string]$Token)
{
   $path = "\\root\OLD folder\"

   $fullpath = $path + $Store
   $fullpath = [uri]::EscapeDataString("$fullpath")
   $fullpath = [uri]::EscapeDataString("$fullpath")


   $body = "\\root\NEW folder"
   $body = $body | ConvertTo-Json


   $Header2 = @{}
   $Header2["Authorization"] = "Bearer " + $Token

   try
   {
      $response2 = Invoke-restmethod -Uri https://$MCFQDN/Mobicontrol/api/devicegroups/$fullpath/path -ContentType "application/json" -Method PUT -Headers $Header2 -Body $body
   }
   catch
   {
      $($_.Exception.Message)
   }
}

get-content $txtFile | %{

   if($_ -match $pattern)
   {

      $Store = $_
      MoveDir $Store $Token

   }
}

A
Anil
7 years ago

I dont have answer to your problem :) .

but can you please let me know how can we use device movment via api??

steps and pre request required ...?

D
Douglas
7 years ago

I've only been able to get it to work using the API page.

D
Douglas
7 years ago

I have, still comes up with the same (403) Forbidden error.

D
Douglas
7 years ago

With a great deal of help from TJ Bukoski, I was able to hack together three scripts to move directories in mass.

This is NOT a safe, robust, or "good" example of powershell scripting, and should not be used in production. I am only posting it so that people who would like to learn more have a place to start from.

Main script MoveIt.ps1:

#Call the Token generation script to use to make calls to the API
. .\Token.ps1
GetToken

$txtFile="E:\Powershell Scripts\stores.txt"; # File with list of new folder-names
$pattern="\d+"; # Pattern that lines must match


get-content $txtFile | %{

   if($_ -match $pattern)
   {
      $Name = $_
      . .\Move.ps1
      MoveDir $Name $Token

   }
}

Script that makes the API call, Move.ps1:


function MoveDir ([string]$Name, [string]$Token)
{

   $path = "\\Root\Old Folder\"

   $fullpath = $path + $Name
   $fullpath = [uri]::EscapeDataString("$fullpath")
   $fullpath = [uri]::EscapeDataString("$fullpath")



   $body = "\\Root\New folder"
   $body = $body | ConvertTo-Json


   $Header2 = @{}
   $Header2["Authorization"] = "Bearer " + $Token

   {
      $response2 = Invoke-restmethod -Uri https://$MCFQDN/Mobicontrol/api/devicegroups/$fullpath/path -ContentType "application/json" -Method PUT -Headers $Header2 -Body $body
   }
   catch
   {
      $($_.Exception.Message)
   }
}

The Token script that TJ supplied as a function, Token.ps1:

function GetToken
{

   $MCUsername = "MobiControl username goes here"
   $MCPassword = "MobiControl Password goes here"
   $MCFQDN = "MobiControl FQDN Goes here"
   $ClientID = "MobiControl API Client ID Goes here"
   $ClientSecret = "MobiControl Client Secret Goes here"


    # You may want to figure out a way to encrypt the Password and the Secret, that's best practice

    $IDSecret = $ClientID + ":" + $ClientSecret
    $EncodedIDSecret = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($IDSecret))

    $Body = @{}
    $Body["grant_type"]="password"
    $Body["username"]=$MCUsername
    $Body["password"]=$MCPassword

    $Header = @{}
    $Header["Authorization"] = "Basic " + $EncodedIDSecret

    try
    {
    $response = Invoke-restmethod -Uri  https://$MCFQDN/mobicontrol/api/token -Method POST -Headers $Header -Body $Body
    }
    catch
    {
    $($_.Exception.Message)
    }

    $Token = $response.access_token

    Write-Host "My MobiControl API Token is: $Token"
}

TB
TJ Bukoski
7 years ago

I managed to get it to work with the following script against my server by hardcoding some values:

$IDSecret = $ClientID + ":" + $ClientSecret 
$EncodedIDSecret = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($IDSecret))

$Body = @{}
$Body["grant_type"]="password"
$Body["username"]=$MCUsername
$Body["password"]=$MCPassword

$Header = @{}
$Header["Authorization"] = "Basic " + $EncodedIDSecret

# Debug lines
write-host "My IDSecret is $IDSecret"
write-host "My Header is " ($Header | Out-String)
write-host "My Body is " ($body | Out-String )
# Debug lines

try
{
$response = Invoke-restmethod -Uri https://$MCFQDN/mobicontrol/api/token -Method POST -Headers $Header -Body $Body
}
catch
{
$($_.Exception.Message)
}

$Token = $response.access_token

Write-Host "My MobiControl API Token is: $Token"


$txtFile="E:\Powershell Scripts\test.txt"; # File with list of folder-names to be moved
$pattern="\d+";


function MoveDir ([string]$Store, [string]$Token)
{
$path = "\\APITest\1 OLD\"

$fullpath = $path + $Store
$fullpath = [uri]::EscapeDataString("$fullpath")
$fullpath = [uri]::EscapeDataString("$fullpath")


$body = "\\APITest\2 NEW"
$body = $body | ConvertTo-Json


$Header2 = @{}
$Header2["Authorization"] = "Bearer " + $Token




try
{
$response2 = Invoke-restmethod -Uri https://$MCFQDN/Mobicontrol/api/devicegroups/$fullpath/path -ContentType "application/json" -Method PUT -Headers $Header2 -Body $body
}
catch
{
$($_.Exception.Message)
}
}

#get-content $txtFile | %{

# if($_ -match $pattern)
# {

# $Store = $_
MoveDir "Test" $Token

# }
#}
PB
Patrick B
6 years ago

First off, thank you! This is just what I needed to start using PowerShell to run some tedious cleanup tasks.


When I tried running the script to validate the $Token I would receive a SSL/TLS error like this:


Invoke-WebRequest : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.


I ended up using this script to bypass the certificate check in Invoke-WebRequest. 


https://blog.ukotic.net/2017/08/15/could-not-establish-trust-relationship-for-the-ssltls-invoke-webrequest/


This is not the desired method, do you have any recommendations on how to do this in the most secure fashion?

Thanks,

Patrick

I managed to get it to work with the following script against my server by hardcoding some values:

$IDSecret = $ClientID + ":" + $ClientSecret 
$EncodedIDSecret = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($IDSecret))

$Body = @{}
$Body["grant_type"]="password"
$Body["username"]=$MCUsername
$Body["password"]=$MCPassword

$Header = @{}
$Header["Authorization"] = "Basic " + $EncodedIDSecret

# Debug lines
write-host "My IDSecret is $IDSecret"
write-host "My Header is " ($Header | Out-String)
write-host "My Body is " ($body | Out-String )
# Debug lines

try
{
$response = Invoke-restmethod -Uri https://$MCFQDN/mobicontrol/api/token -Method POST -Headers $Header -Body $Body
}
catch
{
$($_.Exception.Message)
}

$Token = $response.access_token

Write-Host "My MobiControl API Token is: $Token"


$txtFile="E:\Powershell Scripts\test.txt"; # File with list of folder-names to be moved
$pattern="\d+";


function MoveDir ([string]$Store, [string]$Token)
{
$path = "\\APITest\1 OLD\"

$fullpath = $path + $Store
$fullpath = [uri]::EscapeDataString("$fullpath")
$fullpath = [uri]::EscapeDataString("$fullpath")


$body = "\\APITest\2 NEW"
$body = $body | ConvertTo-Json


$Header2 = @{}
$Header2["Authorization"] = "Bearer " + $Token




try
{
$response2 = Invoke-restmethod -Uri https://$MCFQDN/Mobicontrol/api/devicegroups/$fullpath/path -ContentType "application/json" -Method PUT -Headers $Header2 -Body $body
}
catch
{
$($_.Exception.Message)
}
}

#get-content $txtFile | %{

# if($_ -match $pattern)
# {

# $Store = $_
MoveDir "Test" $Token

# }
#}