Difference between revisions of "Scripting"

From ProVide DocWiki
Jump to: navigation, search
m (Small corrections and reworded certain sentences.)
 
(One intermediate revision by the same user not shown)
Line 380: Line 380:
 
   $t-close; </syntaxhighlight>
 
   $t-close; </syntaxhighlight>
 
Script submitted by Roi
 
Script submitted by Roi
 +
 +
 +
=== Exporting and Importing Users to and from ProVide ===
 +
 +
The following powershell scripts allows you to export and import ProVide users to and from a file.
 +
 +
You need a ProVide with the Build-Date of 2020-03-25 or later to use this functionality.
 +
 +
If you export/import the admin account, please make sure to remember the password.
 +
 +
 +
'''Instructions'''
 +
 +
Simply copy and paste the scripts into a .ps1 file.
 +
 +
Adjust the following parameters to match your setup.
 +
 +
'''$adminHost''' To the IP address of the server.
 +
 +
'''$adminPort''' To your admin port if you have changed it in settings.ini
 +
 +
'''$adminUser''' To your administrator account name.
 +
 +
'''$adminPass''' To the administrator account password.
 +
 +
 +
To use the scripts you simply run
 +
 +
ExportProVideAccounts.ps1 -ExportToFile "filename.bck"
 +
 +
ImportProVideAccounts.ps1 -ImportFromFile "filename.bck"
 +
 +
You can also just run the script and you get to enter the name of a file you want to export/import to/from.
 +
 +
The export script will create a new file if there are none, and overwrite existing ones with the same name.
 +
 +
 +
'''ExportProVideAccounts.ps1'''
 +
 +
<syntaxhighlight>
 +
# A simple account export script for ProVide Server
 +
#
 +
param ([Parameter(Mandatory=$true)] [string] $ExportToFile)
 +
try {
 +
$adminHost = "localhost"
 +
$adminPort = 3145
 +
$adminUser = "admin"
 +
$adminPass = ""
 +
 +
Write-Host "Connecting to $adminHost on port $adminPort ... " -NoNewLine
 +
try {
 +
$socket = New-Object System.Net.Sockets.TcpClient($adminHost, $adminPort)
 +
Write-Host -ForegroundColor Green "OK"
 +
} catch {
 +
Write-Host -ForegroundColor Red "failed"
 +
exit -1
 +
}
 +
 +
$stream = $socket.GetStream()
 +
$writer = New-Object System.IO.StreamWriter($stream)
 +
$reader = New-Object System.IO.StreamReader($stream)
 +
$writer.AutoFlush = $true
 +
 +
function ExpectResponseStart {
 +
$response = $reader.ReadLine()
 +
if (-not $response.StartsWith($args[0])) {
 +
Write-Host -ForegroundColor Red "Expected response start ""$($args[0])"" but got ""$response""."
 +
exit -1
 +
}
 +
}
 +
 +
function ExtractItems {
 +
Write-Host "Listing $($args[0])..."
 +
$writer.WriteLine($args[1])
 +
$items = @()
 +
$response = $reader.ReadLine()
 +
if ($response.Substring(3,1) -eq "-") {
 +
$items += $response.Substring(4)
 +
}
 +
while ($response.StartsWith("200-")) {
 +
$response = $reader.ReadLine()
 +
if ($response.Substring(3,1) -eq "-") {
 +
$items += $response.Substring(4)
 +
}
 +
}
 +
 +
Write-Host "Extracting $($args[0])..."
 +
foreach ($item in $items) {
 +
$data = @()
 +
$writer.WriteLine("$($args[2]) ""$item""");
 +
$response = $reader.ReadLine()
 +
$data += $response.Substring(4)
 +
while ($response.StartsWith("200-")) {
 +
$response = $reader.ReadLine()
 +
$data += $response.Substring(4)
 +
}
 +
 +
$content = ConvertTo-Json -Compress $data
 +
Add-Content -Path $ExportToFile -Encoding Unicode -Value $content
 +
}
 +
}
 +
 +
ExpectResponseStart "220 "
 +
$writer.WriteLine("USER $adminUser")
 +
ExpectResponseStart "331 "
 +
$writer.WriteLine("PASS $adminPass")
 +
ExpectResponseStart "230 "
 +
$writer.WriteLine("OPTS UTF8 ON")
 +
ExpectResponseStart "200 "
 +
 +
rm $ExportToFile -ErrorAction Ignore
 +
ExtractItems "users" "LISTUSERS" "GETUSER"
 +
ExtractItems "groups" "LISTGROUPS" "GETGROUP"
 +
 +
Write-Host "Done."
 +
} finally {
 +
if ($reader) { $reader.Close() }
 +
if ($writer) { $writer.Close() }
 +
if ($stream) { $stream.Close() }
 +
}
 +
</syntaxhighlight>
 +
 +
'''ImportProVideAccounts.ps1'''
 +
 +
<syntaxhighlight>
 +
# A simple account import script for ProVide Server
 +
#
 +
param ([Parameter(Mandatory=$true)] [string] $ImportFromFile)
 +
try {
 +
$adminHost = "localhost"
 +
$adminPort = 3145
 +
$adminUser = "admin"
 +
$adminPass = ""
 +
 +
Write-Host "Connecting to $adminHost on port $adminPort ... " -NoNewLine
 +
try {
 +
$socket = New-Object System.Net.Sockets.TcpClient($adminHost, $adminPort)
 +
Write-Host -ForegroundColor Green "OK"
 +
} catch {
 +
Write-Host -ForegroundColor Red "failed"
 +
exit -1
 +
}
 +
 +
$stream = $socket.GetStream()
 +
$writer = New-Object System.IO.StreamWriter($stream)
 +
$reader = New-Object System.IO.StreamReader($stream)
 +
$writer.AutoFlush = $true
 +
 +
function ExpectResponseStart {
 +
$response = $reader.ReadLine()
 +
if (-not $response.StartsWith($args[0])) {
 +
Write-Host -ForegroundColor Red "Expected response start ""$($args[0])"" but got ""$response""."
 +
exit -1
 +
}
 +
}
 +
 +
function ImportItem {
 +
        $data = ConvertFrom-Json $args[0]
 +
        if ($data[0].StartsWith("User")) {
 +
            $username = $data[0].Substring(9)
 +
            $password = $data[1].Substring(9)
 +
    Write-Host "Importing user ""$username""..."
 +
            $writer.WriteLine("SETUSER ""$username"" ""$password""")
 +
        } elseif ($data[0].StartsWith("Group")) {
 +
            $groupname = $data[0].Substring(10)
 +
    Write-Host "Importing group ""$groupname""..."
 +
            $writer.WriteLine("SETGROUP ""$groupname""")
 +
        }
 +
        foreach ($row in $data) {
 +
            $writer.WriteLine($row)
 +
        }
 +
        if (-not $data[-1] -eq ".") {
 +
            $writer.WriteLine(".")
 +
        }
 +
        ExpectResponseStart "200 "
 +
}
 +
 +
ExpectResponseStart "220 "
 +
$writer.WriteLine("USER $adminUser")
 +
ExpectResponseStart "331 "
 +
$writer.WriteLine("PASS $adminPass")
 +
ExpectResponseStart "230 "
 +
$writer.WriteLine("OPTS UTF8 ON")
 +
ExpectResponseStart "200 "
 +
 +
foreach ($line in Get-Content $ImportFromFile) {
 +
        ImportItem $line
 +
    }
 +
 +
Write-Host "Done."
 +
} finally {
 +
if ($reader) { $reader.Close() }
 +
if ($writer) { $writer.Close() }
 +
if ($stream) { $stream.Close() }
 +
}
 +
 +
</syntaxhighlight>

Latest revision as of 08:32, 26 March 2020

These scripts utilizes the administration protocol to manage the server from custom applications. This technique may be used to integrate ProVide with custom systems, such as web applications or business systems.

If you wish to see how you can start cmd, powershell etc. scripts from ProVide you can check out these links:
Email example
CMD examples


Of course, if your client supports the proper authentication exchange ProVide is able to encrypt the API connection using a regular "AUTH TLS" command (used frequently in for instance FTPS connections).


The easiest way to explore the scripting API is to use a simple telnet application (included with Windows) and connect to the admin port (default 3145):

telnet localhost 3145
220 .
user admin
331 User name received, need password.
pass abc
230 User logged in, proceed.
help
214-The following commands are recognized:
214- PASSWD
214- LISTUSERS
214- ADDUSER
214- GETUSER
214- SETUSER
214- DELUSER
214- SETGROUP
214- DELGROUP
214- SETRESOURCE
214- GETRESOURCE
214- ADDRESOURCE
214- DELRESOURCE
214-
214 For more detailed information, use HELP <COMMAND>.

Examples

Control ProVide with PHP

Connect to server, create accounts, manage resources

<?php 
   /** 
   * Class for ftp-user handling 
   * @author shredder 
   * @version 1.0 
   **/ 
    
   class ftp { 
       
      private $fp; 
      private $commandlog; 
       
      /** 
      * Opens a socket connection to a server, params are read 
      * from database 
      * @param string $host   FTP server address 
      * @param int $port      FTP server port 
      * @param string $user   Adminname 
      * @param string $pass   Adminpassword 
      **/ 
      public function connect($host, $port, $user, $pass) { 
          
         // Open socket connection 
         $this->fp = fsockopen($host,$port); 
          
         // Retrieve welcome message ("200.") 
         $this->commandlog .= "<tr><td>".date("i:s")."</td><td>".fread($this->fp, 1000)."</td></tr>"; 
          
         // Send admin username 
         fwrite($this->fp,"user $user\n"); 
         $this->commandlog .= "<tr><td>".date("i:s")."</td><td>".fread($this->fp, 1000)."</td></tr>"; 
          
         // Send admin password 
         fwrite($this->fp,"pass $pass\n"); 
         $this->commandlog .= "<tr><td>".date("i:s")."</td><td>".fread($this->fp, 1000)."</td></tr>"; 
          
      } 
       
      /** 
      * Creates a user with a specific group membership and/or 
      * a specific FTP-directory with one resource 
      * @param string $username 
      * @param string $password 
      * @param string $realname 
      * @param string $ftppath 
      * @param string $path 
      * @param string $group 
      * @return bool    FALSE if user already exists 
      **/ 
      public function createUser($username, $password, $realname, $ftppath, $path, $group) { 
          
         // Adds a specific user 
         fwrite($this->fp,"adduser \"$username\" \"$password\" \"$realname\" \"$ftppath\" \"$path\" \"$group\"\n"); 
         $message = fread($this->fp, 1000); 
         $this->commandlog .= "<tr><td>".date("i:s")."</td><td>$message</td></tr>"; 
          
         if ($this->isError($message)) { 
             
            return false; 
             
         } else { 
             
            return true; 
             
         } 
          
      } 
       
      /** 
      * Adds a ressource to a user or a group 
      * @param string $username 
      * @param string $ftppath 
      * @param string $path 
      * @param string $rights 
      * @return bool 
      **/ 
      public function addResource($username, $ftppath, $path, $rights) { 
          
         fwrite($this->fp,"addresource \"$username\" \"$ftppath\" \"$path\" \"$rights\"\n"); 
         $message = fread($this->fp, 1000); 
         $this->commandlog .= "<tr><td>".date("i:s")."</td><td>$message</td></tr>"; 
          
         if ($this->isError($message)) { 
             
            return false; 
             
         } else { 
             
            return true; 
             
         } 
      } 
       
      /** 
      * Sets a ressource of a user or a group 
      * @param string $username 
      * @param string $ftppath 
      * @param string $path 
      * @param string $rights 
      * @return bool 
      **/ 
      public function setResource($username, $ftppath, $path, $rights) { 
          
         fwrite($this->fp,"setresource \"$username\" \"$ftppath\" \"$path\" \"$rights\"\n"); 
         $message = fread($this->fp, 1000); 
         $this->commandlog .= "<tr><td>".date("i:s")."</td><td>$message</td></tr>"; 
          
         if ($this->isError($message)) { 
             
            return false; 
             
         } else { 
             
            return true; 
             
         } 
      } 
       
      /** 
      * Changes the password of a specific user 
      * @param string $username 
      * @param string $password 
      * @return bool 
      **/ 
      public function changePassword($username, $password) { 
          
         fwrite($this->fp, "passwd \"$username\" \"$password\"\n"); 
         $message = fread($this->fp, 1000); 
         $this->commandlog .= "<tr><td>".date("i:s")."</td><td>$message</td></tr>"; 
          
         if ($this->isError($message)) { 
             
            return false; 
             
         } else { 
             
            return true; 
             
         } 
          
      } 
       
      /** 
      * Checks if the command was succesful 
      * @param string $message 
      * @return bool 
      **/ 
      private function isError($message) { 
          
         if (substr_count($message, "500")) { 
             
            return false; 
             
         } else { 
          
            return true; 
             
         } 
          
      } 
       
      /** 
      * Returns command log 
      * @return string 
      **/ 
      public function getCommandlog() { 
          
         $this->commandlog = "<table border=1>".$this->commandlog."</table>"; 
         return $this->commandlog; 
          
      } 
       
   } 
?>

Script submitted by MasonSolutions and ReggaeGandalf

Extract information from ProVide with PHP

Extract statistics information

//Shows user-statistics for ProVide 
  //Created by idvis@seznam.cz 
  
  $provideaccountsdir='c:/Program Files/ProVide/accounts/'; //directory of ProVide accounts directory 
  
  function readvalue($astr,$avalue){ 
    if (strpos($astr,$avalue)===false) 
      $result=''; 
    else{  
      $result=substr($astr,strpos($astr,$avalue)+strlen($avalue)); 
      $result=substr($result,0,strpos($result,chr(13).chr(10))); 
    } 
    return $result; 
  } 
  
  function mb($avalue){ 
    if ($avalue=='') 
      $avalue=0; 
    return number_format(round($avalue/(1024*1024),2),2); 
  } 

  //---------------Main code--------------- 
  echo '<html><head><meta http-equiv="content-type" content="text/html; charset=windows-1250">'; 
  echo '<style>.left{text-align:left;} body,table{font: 11px verdana,arial,helvetica,sans-serif;} th,td{text-align:right; padding-right:1em;}</style></head><body><table>'; 
  echo '<tr><th class="left">FTP Username</th><th>Logins</th><th class="left">Last login</th><th class="left">Last IP</th>' 
       .'<th>Downl. files</th><th>Upl. files</th><th>Download [MB]</th><th>Upload [MB]</th></tr>'; 
  $sumdown=0; 
  $sumup=0; 
  foreach (glob($provideaccountsdir."*.uac") as $filename) { 
    $s=file_get_contents($filename); 
    $username=readvalue($s,"Username="); 
    $logins=readvalue($s,"{Logins: "); 
    if ($logins!=''){ 
      $lastlogin=readvalue($s,"{Last Login: "); 
      $lastknownip=readvalue($s,"{Last Known IP: "); 
      $filesuploaded=readvalue($s,"{Files Uploaded: "); 
      $bytesuploaded=readvalue($s,"{Bytes Uploaded: "); 
      $filesdownloaded=readvalue($s,"{Files Downloaded: "); 
      $bytesdownloaded=readvalue($s,"{Bytes Downloaded: "); 
      $sumdown+=$bytesdownloaded; 
      $sumup+=$bytesuploaded; 
      echo "<tr><td class='left'>$username</td><td>$logins</td><td class='left'>$lastlogin</td><td class='left'>$lastknownip</td>" 
          ."<td>$filesdownloaded</td><td>$filesuploaded</td><td>".mb($bytesdownloaded)."</td><td>".mb($bytesuploaded)."</td></tr>"; 
    } 
  } 
  echo "<tr><th colspan='6'>Total:</th><th>".mb($sumdown)."</th><th>".mb($sumup)."</th></tr>"; 
  
  echo '</table></body></html>'; 
  
?>

Script submitted by Idvis

Control ProVide with PERL

Connect to server, create accounts, manage resources

#!"c:/perl/bin/perl.exe" 

use Strict; 
use Net::Telnet; 
use CGI; 
   $CGI::POST_MAX=1024 * 5;  # max 5K posts 
       $CGI::DISABLE_UPLOADS = 1;  # no uploads 
use File::Path::Stderr; 

my $query = new CGI; 
my $t = new Net::Telnet (); 



   my $port = 3145; 
   my $admin_uname = "Admin"; 
   my ($admin_passwd, $uname, $passwd, $real_name, $new_domain, $vhpath); 

   $admin_passwd = $query->param('Admin_pass'); 
   $uname = $query->param('new_user'); 
   $passwd = $query->param('new_password'); 
   $real_name = $query->param('real_name'); 
   $domain_name = $query->param('domain'); 
   $vhpath = "c\:\\sites\\vh\\$domain_name\.vh"; 

   mkpath("c\:\\sites\\$domain_name\\logs"); 
   mkpath("c\:\\sites\\$domain_name\\httpdocs"); 
   mkpath("c\:\\sites\\$domain_name\\cgi-bin"); 

   my @lines; 
   $lines[0] = '<VirtualHost *:80>'; 
   $lines[1] = '   ServerAdmin admin@dj69.com'; 
   $lines[2] = '   DocumentRoot C:/sites/'.$domain_name.'/httpdocs/'; 
   $lines[3] = '   ServerName '.$domain_name; 
   $lines[4] = '   ServerAlias www.'.$domain_name; 
   $lines[5] = '   ErrorLog C:/sites/'.$domain_name.'/logs/error_log'; 
   $lines[6] = '   CustomLog C:/sites/'.$domain_name.'/logs/access_log common'; 
   $lines[7] = '   ScriptAlias /cgi-bin/ C:/sites/'.$domain_name.'/cgi-bin/'; 
   $lines[8] = '<Directory "C:/sites/'.$domain_name.'/httpdocs/">'; 
   $lines[9] = '   Options Includes'; 
   $lines[10] = '   AllowOverride None'; 
   $lines[11] = '   Order allow,deny'; 
   $lines[12] = '   Allow from all'; 
   $lines[13] = '</Directory>'; 
   $lines[14] = '</VirtualHost>'; 

   open FH, ">$vhpath"; 
   my $listitem; 
   foreach $listitem ( @lines ) 
   { 
      print FH $listitem, "\n"; 
   } 


   close(FH); 

print "Content-type:text/html\n\n"; 

   $t->open(port => $port); 
print "port open\n"; 

# Next line is not needed from some reason..... 
#   $t->waitfor('/200\s\./'); 
   print 'Got 220 (Got in)<br>'; 

# sending admin's user name 
   $t->print('user ', $admin_uname); 
   print "gave username<br>"; 

# checking for the correct response (331). 
   $t->waitfor('/331 .*/') or die "dowant pass\n"; 
   print "Got 331 User name received, need password.<br>"; 

# sending admin's password 
   $t->print('pass ', $admin_passwd); 
   print "gave password.<br>"; 

#checking for the correct response (230). 
   $t->waitfor('/230 .*/') or die "pass is not correct\n"; 
   print "got 230 User logged in, proceed.<br>"; 

#Adding the new user 
   print "Adding new user $uname"; 
   $t->print('ADDUSER "', $uname, '" "', $passwd, '" "', $real_name, '"'); 
   $t->waitfor('/200 .*/') or die "user has not been creates\n"; 
   print "Got 200 User created successfully.<br>"; 

#connecting resources to the user. 
   print "connecting resources"; 
   $t->print('SETRESOURCE "', $uname, '" "cgi-bin" "c\:\\sites\\', $domain_name, '\cgi-bin" "RF,WF,DF,AF,LD,MD,DD,RR"'); 
   $t->waitfor('/200 .*/') or die "user did not update\n"; 
print "Got 200 User(s) updated successfully.<br>"; 
   $t->print('SETRESOURCE "', $uname, '" "httpdocs" "c\:\\sites\\', $domain_name, '\httpdocs" "RF,WF,DF,AF,LD,MD,DD,RR"'); 
   $t->waitfor('/200 .*/') or die "user did not update\n"; 
print "Got 200 User(s) updated successfully.<br>"; 
   $t->print('SETRESOURCE "', $uname, '" "logs" "c\:\\sites\\', $domain_name, '\logs" "RF,LD,RR"'); 
   $t->waitfor('/200 .*/') or die "user did not update\n"; 
print "Got 200 User(s) updated successfully.<br>"; 



#   print "deleting user\n"; 
#   $t->print('DELUSER "', $uname, '"'); 
#   $t->waitfor('/200 .*/') or die "user has not been deleted\n"; 
#print "User(s) removed successfully.\n"; 

print "Quitting\n"; 
   $t->print('quit'); 
   $t-close;

Script submitted by Roi


Exporting and Importing Users to and from ProVide

The following powershell scripts allows you to export and import ProVide users to and from a file.

You need a ProVide with the Build-Date of 2020-03-25 or later to use this functionality.

If you export/import the admin account, please make sure to remember the password.


Instructions

Simply copy and paste the scripts into a .ps1 file.

Adjust the following parameters to match your setup.

$adminHost To the IP address of the server.

$adminPort To your admin port if you have changed it in settings.ini

$adminUser To your administrator account name.

$adminPass To the administrator account password.


To use the scripts you simply run

ExportProVideAccounts.ps1 -ExportToFile "filename.bck"

ImportProVideAccounts.ps1 -ImportFromFile "filename.bck"

You can also just run the script and you get to enter the name of a file you want to export/import to/from.

The export script will create a new file if there are none, and overwrite existing ones with the same name.


ExportProVideAccounts.ps1

# A simple account export script for ProVide Server
#
param ([Parameter(Mandatory=$true)] [string] $ExportToFile)
try {
	$adminHost = "localhost"
	$adminPort = 3145
	$adminUser = "admin"
	$adminPass = ""

	Write-Host "Connecting to $adminHost on port $adminPort ... " -NoNewLine
	try {
		$socket = New-Object System.Net.Sockets.TcpClient($adminHost, $adminPort)
		Write-Host -ForegroundColor Green "OK"
	} catch	{
		Write-Host -ForegroundColor Red "failed"
		exit -1
	}

	$stream = $socket.GetStream()
	$writer = New-Object System.IO.StreamWriter($stream)
	$reader = New-Object System.IO.StreamReader($stream)
	$writer.AutoFlush = $true

	function ExpectResponseStart {
		$response = $reader.ReadLine()
		if (-not $response.StartsWith($args[0])) {
			Write-Host -ForegroundColor Red "Expected response start ""$($args[0])"" but got ""$response""."
			exit -1
		}
	}

	function ExtractItems {
		Write-Host "Listing $($args[0])..."
		$writer.WriteLine($args[1])
		$items = @()
		$response = $reader.ReadLine()
		if ($response.Substring(3,1) -eq "-") {
			$items += $response.Substring(4)
		}
		while ($response.StartsWith("200-")) {
			$response = $reader.ReadLine()
			if ($response.Substring(3,1) -eq "-") {
				$items += $response.Substring(4)
			}
		}

		Write-Host "Extracting $($args[0])..."
		foreach ($item in $items) {
			$data = @()
			$writer.WriteLine("$($args[2]) ""$item""");
			$response = $reader.ReadLine()
			$data += $response.Substring(4)
			while ($response.StartsWith("200-")) {
				$response = $reader.ReadLine()
				$data += $response.Substring(4)
			}

			$content = ConvertTo-Json -Compress $data
			Add-Content -Path $ExportToFile -Encoding Unicode -Value $content
		}
	}

	ExpectResponseStart "220 "
	$writer.WriteLine("USER $adminUser")
	ExpectResponseStart "331 "
	$writer.WriteLine("PASS $adminPass")
	ExpectResponseStart "230 "
	$writer.WriteLine("OPTS UTF8 ON")
	ExpectResponseStart "200 "

	rm $ExportToFile -ErrorAction Ignore
	ExtractItems "users" "LISTUSERS" "GETUSER"
	ExtractItems "groups" "LISTGROUPS" "GETGROUP"

	Write-Host "Done."
} finally {
	if ($reader) { $reader.Close() }
	if ($writer) { $writer.Close() }
	if ($stream) { $stream.Close() }
}

ImportProVideAccounts.ps1

# A simple account import script for ProVide Server
#
param ([Parameter(Mandatory=$true)] [string] $ImportFromFile)
try {
	$adminHost = "localhost"
	$adminPort = 3145
	$adminUser = "admin"
	$adminPass = ""

	Write-Host "Connecting to $adminHost on port $adminPort ... " -NoNewLine
	try {
		$socket = New-Object System.Net.Sockets.TcpClient($adminHost, $adminPort)
		Write-Host -ForegroundColor Green "OK"
	} catch	{
		Write-Host -ForegroundColor Red "failed"
		exit -1
	}

	$stream = $socket.GetStream()
	$writer = New-Object System.IO.StreamWriter($stream)
	$reader = New-Object System.IO.StreamReader($stream)
	$writer.AutoFlush = $true

	function ExpectResponseStart {
		$response = $reader.ReadLine()
		if (-not $response.StartsWith($args[0])) {
			Write-Host -ForegroundColor Red "Expected response start ""$($args[0])"" but got ""$response""."
			exit -1
		}
	}

	function ImportItem {
        $data = ConvertFrom-Json $args[0]
        if ($data[0].StartsWith("User")) {
            $username = $data[0].Substring(9)
            $password = $data[1].Substring(9)
		    Write-Host "Importing user ""$username""..."
            $writer.WriteLine("SETUSER ""$username"" ""$password""")
        } elseif ($data[0].StartsWith("Group")) {
            $groupname = $data[0].Substring(10)
		    Write-Host "Importing group ""$groupname""..."
            $writer.WriteLine("SETGROUP ""$groupname""")
        }
        foreach ($row in $data) {
            $writer.WriteLine($row)
        }
        if (-not $data[-1] -eq ".") {
            $writer.WriteLine(".")
        }
        ExpectResponseStart "200 "
	}

	ExpectResponseStart "220 "
	$writer.WriteLine("USER $adminUser")
	ExpectResponseStart "331 "
	$writer.WriteLine("PASS $adminPass")
	ExpectResponseStart "230 "
	$writer.WriteLine("OPTS UTF8 ON")
	ExpectResponseStart "200 "

	foreach ($line in Get-Content $ImportFromFile) {
        ImportItem $line
    }

	Write-Host "Done."
} finally {
	if ($reader) { $reader.Close() }
	if ($writer) { $writer.Close() }
	if ($stream) { $stream.Close() }
}