Powershell for users & admins to create & manage FTPaccounts

Moderator: Project members

Post Reply
Message
Author
kevmaitland
Contributor
Posts: 8
Joined: 2014-05-13 12:41
First name: Kev
Last name: Maitland

Powershell for users & admins to create & manage FTPaccounts

#1 Post by kevmaitland » 2014-05-13 13:23

Hello everyone,

I've written some Powershell scripts that do the following:
  • Allow users to create FTP accounts in a standardised way without access to the FileZilla Server console
  • Allow users to create FTP accounts when they have minimal permissions on their local computer and the FileZilla Server
  • Reset FTP account passwords and reactivate disabled accounts without administrator intervention
  • Automatically disable FTP accounts after a set period of time
  • Automatically archive FTP folders and delete associated FTP accounts that have been disabled for a set period of time
  • Automatically e-mail the user that created/last modified the FTP account that these automated housekeeping tasks will occur
They basically allow our domain users to provision FTP accounts via a Remote Desktop server on behalf of clients, without the intervention of the IT team. The admin scripts are run daily as scheduled tasks and e-mail the relevant users 7 days (and again 1 day) before the FTP accounts are automatically disabled. The users can prevent this happening by changing the password on the FTP account (via a second script). If they don't, then the FTP account will be deleted from FileZilla and any files/folders are automatically moved to an archive area. All the housekeeping is therefore done automatically on behalf of the IT Team.

I've outlined any requirements and assumptions made in the headers of each file, so hopefully it should make sense. I wrote it in Powershell v4, but I think it should be backwardly compatible. The code tags make it look pretty horrendous, but if you cut-and-paste it into ISE, you can fold up the functions and make it a lot more readable. It took a while, so hopefully they'll save someone else out there some time :)
Last edited by kevmaitland on 2014-05-13 13:38, edited 1 time in total.

kevmaitland
Contributor
Posts: 8
Joined: 2014-05-13 12:41
First name: Kev
Last name: Maitland

Re: Powershell for users & admins to create & manage FTPacco

#2 Post by kevmaitland » 2014-05-13 13:25

FTP_NewFileZillaUser

Code: Select all

#Script to create a new user in FileZilla
#Uses the Comments XML element under the User node for auditing
#
#Can be executed on a PC/server other than the FileZilla server (e.g. Remote Desktop server)
#
#Requirements:
#- A template FTP user account to be created on the FileZilla server (this makes it easy to set default option specific to your environment, e.g. Enforce SSL)
#- Additional Groups to be created manually in FileZilla Server, and to have the corresponding filesystem folders created manually too.
#- The user running this script needs Modify Share permissions on the $ftpDataShare share to create the directory for the new account
#- The user running this script needs NTFS Write permissions on the $ftpDataShare\$ftpGroup directories to create the directory for the new account
#- Editing the FileZilla XML:
#  - The "%PROGRAM FILES (x86)%\FileZilla Server" directory on the FileZilla server to be shared as "FileZillaServer$" and the user running this script needs Change permissions on the share
#  - The user running this script needs NTFS Modify permissions on the "\\$filezillaServer\FileZillaServer$\FileZilla Server.xml"
#- Reloading the FileZilla Config
#  - Set-ExecutionPolicy to be set to RemoteSigned (or lower) on the computer running this script and on the FileZilla server (unless you sign the scripts yourself)
#  - A script that contains the commands required to reload the FileZilla config (otherwise the FileZilla services need to be restarted)
#  - A PSSessionConfiguration on the FileZilla server with a -RunAsCredential with local admin rights and Invoke permission (required for the /reload-config command to work)
#      - This recommends a dedicated local administrator account on the FileZilla server that can be locked down further as required
#
#Does not require:
#- Local Administrator permissions for the user running this script on the computer running this script
#- Local Administrator permissions for the user running this script on the FileZilla server
#
#If you like the script, feel free to pop a beer in the post c/o Kev Maitland - I work at the head office of www.sustain.co.uk :)


$filezillaServer = "yourFileZillaServer"
$ftpDataShare = "yourFTPDataShare"
$localPathToFTPDataShareOnFileZillaServer = "D:" #Used to map user's Home Folder locally, rather than via UNC
$xmlFilePath = "\\$filezillaServer\FileZillaServer$\FileZilla Server.xml"
$psSessionConfigurationNameOnFileZillaServer = "FileZilla"
$reloadFZConfigCmdPath = "\\$filezillaServer\FileZillaServer$\ReloadConfig.ps1"
$formTitle = "Secure FTP User Creation"
$disallowedCharacters = @("\<", "\>", "\:", '\"', "\/", "\\", "\|", "\?", '\*', "\ ", "\'", "\,", "\^") -join '|' #Use RegEx escape character (\) here, not PowerShell (`)
$date = Get-Date

function formCaptureText([string]$formTitle, [string]$formText){
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 

    $objForm = New-Object System.Windows.Forms.Form 
    $objForm.Text = $formTitle
    $objForm.Size = New-Object System.Drawing.Size(300,200) 
    $objForm.StartPosition = "CenterScreen"

    $objForm.KeyPreview = $True
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter") 
        {$script:capturedText = $objTextBox.Text;$objForm.Close()}})
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape") 
        {$objForm.Close();$script:capturedText = ""}})


    $OKButton = New-Object System.Windows.Forms.Button
    $OKButton.Location = New-Object System.Drawing.Size(75,120)
    $OKButton.Size = New-Object System.Drawing.Size(75,23)
    $OKButton.Text = "OK"
    $OKButton.Add_Click({$script:capturedText=$objTextBox.Text;$objForm.Close()})
    $objForm.Controls.Add($OKButton)

    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Size(150,120)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = "Cancel"
    $CancelButton.Add_Click({$objForm.Close();$script:capturedText = ""})
    $objForm.Controls.Add($CancelButton)

    $objLabel = New-Object System.Windows.Forms.Label
    $objLabel.Location = New-Object System.Drawing.Size(10,20) 
    $objLabel.Size = New-Object System.Drawing.Size(280,40) 
    $objLabel.Text = $formText
    $objForm.Controls.Add($objLabel) 

    $objTextBox = New-Object System.Windows.Forms.TextBox 
    $objTextBox.Location = New-Object System.Drawing.Size(10,60) 
    $objTextBox.Size = New-Object System.Drawing.Size(260,20) 
    $objForm.Controls.Add($objTextBox) 

    $objForm.Topmost = $True

    $objForm.Add_Shown({$objForm.Activate()})
    [void] $objForm.ShowDialog()

    $capturedText
    }
function formCaptureSelection([string]$formTitle, [string]$formText, [string[]]$choices){
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 

    $objForm = New-Object System.Windows.Forms.Form 
    $objForm.Text = $formTitle
    $objForm.Size = New-Object System.Drawing.Size(300,200) 
    $objForm.StartPosition = "CenterScreen"

    $objForm.KeyPreview = $True
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter") 
        {$script:capturedSelection = $objTextBox.Text;$objForm.Close()}})
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape") 
        {$objForm.Close();$script:capturedSelection = ""}})


    $OKButton = New-Object System.Windows.Forms.Button
    $OKButton.Location = New-Object System.Drawing.Size(75,120)
    $OKButton.Size = New-Object System.Drawing.Size(75,23)
    $OKButton.Text = "OK"
    $OKButton.Add_Click({$script:capturedSelection=$objListBox.SelectedItem;$objForm.Close()})
    $objForm.Controls.Add($OKButton)

    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Size(150,120)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = "Cancel"
    $CancelButton.Add_Click({$objForm.Close();$script:capturedSelection = ""})
    $objForm.Controls.Add($CancelButton)

    $objLabel = New-Object System.Windows.Forms.Label
    $objLabel.Location = New-Object System.Drawing.Size(10,20) 
    $objLabel.Size = New-Object System.Drawing.Size(280,20) 
    $objLabel.Text = $formText
    $objForm.Controls.Add($objLabel) 

    $objListBox = New-Object System.Windows.Forms.ListBox 
    $objListBox.Location = New-Object System.Drawing.Size(10,40) 
    $objListBox.Size = New-Object System.Drawing.Size(260,20) 
    $objListBox.Height = 80
    foreach ($choice in $choices){
        [void] $objListBox.Items.Add($choice)
        }
    $objForm.Controls.Add($objListBox) 

    $objForm.Topmost = $True
    $objForm.Add_Shown({$objForm.Activate()})
    [void] $objForm.ShowDialog()

    $capturedSelection
    }
function hashMeAPassword([string]$clearText){
    $md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
    $utf8 = new-object -TypeName System.Text.UTF8Encoding
    $passHash = [System.BitConverter]::ToString($md5.ComputeHash($utf8.GetBytes($clearText))).ToLower() -replace "-",""
    $passHash
    }

#Open the XML document so that we can check for duplicate usernames
$xml = [xml](Get-Content $xmlFilePath)

#Generate a form to capture the new account name and perform some validation. Usernames need to converted to lowercase as XML is case sensitive (and everything else is not)
$ftpUsernameValid = $false
$ftpUsername = (formCaptureText $formTitle "Please enter the new username below (don't use spaces or symbols in the username):").ToLower()
while ($ftpUsernameValid -eq $false){
    if ($ftpUsername -eq ""){write-host "Empty username. Exiting now";exit} #If username is empty, quit.
    $ftpUsernameValid = $true
    if ($xml.SelectSingleNode("/FileZillaServer/Users/User[@Name='$ftpUsername']") -ne $null){ #Don't let the user choose an pre-existing username
        $ftpUsernameValid = $false
        $ftpUsername = (formCaptureText $formTitle "Username already in use - please choose another (don't use spaces or symbols):").ToLower()
        }
    if ($ftpUsername -match $disallowedCharacters){ #Make sure that the user hasn't chosen any spaces or symmbols in the account name
        $ftpUsernameValid = $false
        $ftpUsername = (formCaptureText $formTitle "Oi $env:username! I said /don't/ use spaces or symbols! Try again:").ToLower()
        }
    }

#Generate a form to capture the new password and perform some rudimentary validiation
$ftpPassword = formCaptureText $formTitle "Please enter the new (strong) password below:"
while (($ftpPassword.Length -lt 8) -or ($ftpPassword -eq $ftpUsername) -or ($ftpPassword -match "123")){
    if ($ftpPassword -eq ""){write-host "Empty password. Exiting now";exit} #If password is empty, quit. 
    $ftpPassword = formCaptureText $formTitle "Don't be an idiot, $env:username. Enter a proper /strong/ password below. You can generate them at http://strongpasswordgenerator.com/:"
    }

#Generate a form to capture the new account's group (doesn't require additional validation as they are picking from a list)
$ftpGroupsArray = @()
foreach ($ftpGroup in $xml.FileZillaServer.Groups.Group){$ftpGroupsArray += $ftpGroup.Name} #Pull the list of Groups from the FileZilla XML
[Array]::Sort([array]$ftpGroupsArray) #Sort the list of Groups
$ftpGroupsArray += "None" #Add a final "None" option

$ftpGroup = formCaptureSelection "Secure FTP User Creation" "Please select the appropriate group for the new user:" $ftpGroupsArray
if ($ftpGroup -eq ""){write-host "Empty group. Exiting now";exit} #If either values are empty, quit. 



cls
Write-Host -ForegroundColor Yellow "Creating new user: $ftpUsername / $ftpPassword / $ftpGroup"
#------------------------------------------
#---Create the folder structure
#------------------------------------------
Write-Host -ForegroundColor DarkYellow "Creating new folder at: \\$filezillaServer\$ftpDataShare\$ftpGroup\$ftpUsername"
if (!(Test-Path "\\$filezillaServer\$ftpDataShare\$ftpGroup\$ftpUsername")){
    $null = New-Item -ItemType directory -Path "\\$filezillaServer\$ftpDataShare\$ftpGroup\$ftpUsername" 
    $null = New-Item -ItemType directory -Path "\\$filezillaServer\$ftpDataShare\$ftpGroup\$ftpUsername\$ftpUsername"
    }
#------------------------------------------
#---Edit the FileZilla XML to add the new user
#------------------------------------------
Write-Host -ForegroundColor DarkYellow "Adding $ftpUsername to FileZilla"
$passHash = hashMeAPassword $ftpPassword

$newFZUser = ($xml.FileZillaServer.Users.User | ?{$_.Name -eq "TemplateFTPUser"}).clone() #Uses a template user called "TemplateFTPUser" that you've already created in FileZilla through the GUI
$newFZUser.Name = $ftpUsername
$newFZUser.SelectSingleNode("Option[@Name='Pass']").InnerText = $passHash
$newFZUser.SelectSingleNode("Option[@Name='Group']").InnerText = $ftpGroup
$newFZUser.SelectSingleNode("Option[@Name='Enabled']").InnerText = 1
$newFZUser.SelectSingleNode("Option[@Name='Comments']").InnerText = "Created by $env:username on $(get-date $date -Format "yyyy/MM/dd hh:mm:ss") updated by $env:username on $(get-date $date -Format "yyyy/MM/dd hh:mm:ss")"
$newfzuser.permissions.permission.dir = "$localPathToFTPDataShareOnFileZillaServer\$ftpDataShare\$ftpGroup\$ftpUsername"

$null = $xml.DocumentElement.Users.AppendChild($newFZUser)
$xml.Save($xmlFilePath)


#------------------------------------------
#---Reload the FileZilla config to initialise the new user
#------------------------------------------
Write-Host -ForegroundColor DarkYellow "Activating $ftpUsername ..."
Invoke-Command -ComputerName $filezillaServer -FilePath $reloadFZConfigCmdPath -ConfigurationName $psSessionConfigurationNameOnFileZillaServer


Write-Host -ForegroundColor Yellow "User setup complete! Press enter to exit this window"
$null = Read-Host
Last edited by kevmaitland on 2014-05-13 17:10, edited 1 time in total.

kevmaitland
Contributor
Posts: 8
Joined: 2014-05-13 12:41
First name: Kev
Last name: Maitland

Re: Powershell for users & admins to create & manage FTPacco

#3 Post by kevmaitland » 2014-05-13 13:29

FTP_ResetFileZillaUserPassword.ps1

Code: Select all

#Script to allow a user to select an account from FileZilla and reset the password.
#Also reactivates an account if it has been disabled, and uses the Comments XML element under the User node for auditing
#
#Can be executed on a PC/server other than the FileZilla server (e.g. Remote Desktop server)
#
#Requirements:
#- Editing the FileZilla XML:
#  - The "%PROGRAM FILES (x86)%\FileZilla Server" directory on the FileZilla server to be shared as "FileZillaServer$" and the user running this script needs Change permissions on the share
#  - The user running this script needs NTFS Modify permissions on the "\\$filezillaServer\FileZillaServer$\FileZilla Server.xml"
#- Reloading the FileZilla Config
#  - Set-ExecutionPolicy to be set to RemoteSigned (or lower) on the computer running this script and on the FileZilla server (unless you sign the scripts yourself)
#  - A script that contains the commands required to reload the FileZilla config (otherwise the FileZilla services need to be restarted)
#  - A PSSessionConfiguration on the FileZilla server with a -RunAsCredential with local admin rights and Invoke permission (required for the /reload-config command to work)
#      - This recommends a dedicated local administrator account on the FileZilla server that can be locked down further as required
#
#Does not require:
#- Local Administrator permissions for the user running this script on the computer running this script
#- Local Administrator permissions for the user running this script on the FileZilla server
#
#If you like the script, feel free to pop a beer in the post c/o Kev Maitland - I work at the head office of www.sustain.co.uk :)


$filezillaServer = "yourFileZillaServer"
$ftpDataShare = "yourFTPDataShare"
$xmlFilePath = "\\$filezillaServer\FileZillaServer$\FileZilla Server.xml"
$reloadFZConfigCmdPath = "\\$filezillaServer\FileZillaServer$\ReloadConfig.ps1"
$psSessionConfigurationNameOnFileZillaServer = "FileZilla"
$date = Get-Date

$formTitle = "Secure FTP Password Reset"
 
function formCaptureText([string]$formTitle, [string]$formText){
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 

    $objForm = New-Object System.Windows.Forms.Form 
    $objForm.Text = $formTitle
    $objForm.Size = New-Object System.Drawing.Size(300,200) 
    $objForm.StartPosition = "CenterScreen"

    $objForm.KeyPreview = $True
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter") 
        {$script:capturedText = $objTextBox.Text;$objForm.Close()}})
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape") 
        {$objForm.Close();$script:capturedText = ""}})


    $OKButton = New-Object System.Windows.Forms.Button
    $OKButton.Location = New-Object System.Drawing.Size(75,120)
    $OKButton.Size = New-Object System.Drawing.Size(75,23)
    $OKButton.Text = "OK"
    $OKButton.Add_Click({$script:capturedText=$objTextBox.Text;$objForm.Close()})
    $objForm.Controls.Add($OKButton)

    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Size(150,120)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = "Cancel"
    $CancelButton.Add_Click({$objForm.Close();$script:capturedText = ""})
    $objForm.Controls.Add($CancelButton)

    $objLabel = New-Object System.Windows.Forms.Label
    $objLabel.Location = New-Object System.Drawing.Size(10,20) 
    $objLabel.Size = New-Object System.Drawing.Size(280,40) 
    $objLabel.Text = $formText
    $objForm.Controls.Add($objLabel) 

    $objTextBox = New-Object System.Windows.Forms.TextBox 
    $objTextBox.Location = New-Object System.Drawing.Size(10,60) 
    $objTextBox.Size = New-Object System.Drawing.Size(260,20) 
    $objForm.Controls.Add($objTextBox) 

    $objForm.Topmost = $True

    $objForm.Add_Shown({$objForm.Activate()})
    [void] $objForm.ShowDialog()

    $capturedText
    }
function formCaptureSelection([string]$formTitle, [string]$formText, [string[]]$choices){
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 

    $objForm = New-Object System.Windows.Forms.Form 
    $objForm.Text = $formTitle
    $objForm.Size = New-Object System.Drawing.Size(300,200) 
    $objForm.StartPosition = "CenterScreen"

    $objForm.KeyPreview = $True
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter") 
        {$script:capturedSelection = $objTextBox.Text;$objForm.Close()}})
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape") 
        {$objForm.Close();$script:capturedSelection = ""}})


    $OKButton = New-Object System.Windows.Forms.Button
    $OKButton.Location = New-Object System.Drawing.Size(75,120)
    $OKButton.Size = New-Object System.Drawing.Size(75,23)
    $OKButton.Text = "OK"
    $OKButton.Add_Click({$script:capturedSelection=$objListBox.SelectedItem;$objForm.Close()})
    $objForm.Controls.Add($OKButton)

    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Size(150,120)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = "Cancel"
    $CancelButton.Add_Click({$objForm.Close();$script:capturedSelection = ""})
    $objForm.Controls.Add($CancelButton)

    $objLabel = New-Object System.Windows.Forms.Label
    $objLabel.Location = New-Object System.Drawing.Size(10,20) 
    $objLabel.Size = New-Object System.Drawing.Size(280,20) 
    $objLabel.Text = $formText
    $objForm.Controls.Add($objLabel) 

    $objListBox = New-Object System.Windows.Forms.ListBox 
    $objListBox.Location = New-Object System.Drawing.Size(10,40) 
    $objListBox.Size = New-Object System.Drawing.Size(260,20) 
    $objListBox.Height = 80
    foreach ($choice in $choices){
        [void] $objListBox.Items.Add($choice)
        }
    $objForm.Controls.Add($objListBox) 

    $objForm.Topmost = $True
    $objForm.Add_Shown({$objForm.Activate()})
    [void] $objForm.ShowDialog()

    $capturedSelection
    }
function hashMeAPassword([string]$clearText){
    $md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
    $utf8 = new-object -TypeName System.Text.UTF8Encoding
    $passHash = [System.BitConverter]::ToString($md5.ComputeHash($utf8.GetBytes($clearText))).ToLower() -replace "-",""
    $passHash
    }

#Import the FileZilla XML file so that we can reactivate accounts
$xml = [xml](Get-Content $xmlFilePath)
 
#Get a list of active accounts for the user to pick from
$listOfUsernames = @()
foreach ($ftpUsername in $xml.FileZillaServer.Users.User){$listOfUsernames += $ftpUsername.Name}
[Array]::Sort([array]$listOfUsernames)

#Get the user to select the account to reset from $listOfUsernames
$ftpUsername = formCaptureSelection $formTitle "Please select the user to reset their password:" $listOfUsernames
if ($ftpUsername -eq ""){write-host "Empty username. Exiting now";exit} #If either values are empty, quit. 
$FZUserForResetting = $xml.SelectSingleNode("/FileZillaServer/Users/User[@Name='$ftpUsername']")
$FZUserForResettingPassword = $FZUserForResetting.SelectSingleNode("Option[@Name='Pass']")
$FZUserForResettingOldComments = $FZUserForResetting.SelectSingleNode("Option[@Name='Comments']")

#Get a new password
$ftpPassword = formCaptureText $formTitle "Please enter a new, strong password below:"
$passHash = hashMeAPassword $ftpPassword
while (($ftpPassword.Length -lt 8) -or ($ftpPassword -eq $ftpUsername) -or ($ftpPassword -match "123") -or ($passHash -eq $FZUserForResettingPassword.InnerText)){
    if ($ftpPassword -eq ""){write-host "Empty password. Exiting now";exit} #If value is empty, quit. 
    $ftpPassword = formCaptureText $formTitle "Don't be an plonker, $env:username. Enter a proper /strong/ *new* password below. You can generate them at http://strongpasswordgenerator.com/:"
    $passHash = hashMeAPassword $ftpPassword
    }

#Then reactivate the account in the FileZilla XML file and update the Comments element with the LastUpdated and UpdatedBy data
Write-Host -ForegroundColor Yellow "Resetting password for $ftpUsername"
$FZUserForResettingPassword.InnerText = $passHash #This bit overwrites the old password with a new one
$FZUserForResetting.SelectSingleNode("Option[@Name='Enabled']").InnerText = 1 #This re-enables them in case the account has expired
$FZUserForResettingNewComments = ($FZUserForResettingOldComments.InnerText).split(" ")
$FZUserForResettingNewComments[8] = $env:username #Set the "UpdatedBy" username to the current user
$FZUserForResettingNewComments[10] = Get-Date $date -Format yyyy/MM/dd #Set the "LastUpdated" date to the new date
$FZUserForResettingNewComments[11] = Get-Date $date -Format hh:mm:ss #Set the "LastUpdated" time to the new time
$FZUserForResettingNewCommentsAsASingleString = ""
foreach ($word in $FZUserForResettingNewComments){$FZUserForResettingNewCommentsAsASingleString += "$word "} #Rewrite the updated comments into a single long string again
$FZUserForResetting.SelectSingleNode("Option[@Name='Comments']").InnerText = $FZUserForResettingNewCommentsAsASingleString #Assign the final version of the updated comments
$xml.Save($xmlFilePath) #Save the XML data

 
#------------------------------------------
#---Reload the FileZilla config to initialise the new user
#------------------------------------------
Write-Host -ForegroundColor DarkYellow "Activating $ftpUsername ..."
Invoke-Command -ComputerName $filezillaServer -FilePath $reloadFZConfigCmdPath -ConfigurationName $psSessionConfigurationNameOnFileZillaServer

Write-Host -ForegroundColor Yellow "User password reset! Press enter to exit this window"
$null = Read-Host

kevmaitland
Contributor
Posts: 8
Joined: 2014-05-13 12:41
First name: Kev
Last name: Maitland

Re: Powershell for users & admins to create & manage FTPacco

#4 Post by kevmaitland » 2014-05-13 13:31

FTP_UserMaintenance

Code: Select all

#Script to automatically disable old FTP accounts
#Also: 
#- archives very old FTP accounts (moves the data and deletes the account)
#- warns users via e-mail that ftp accounts they have created/updated are due to expire
#- warns users via e-mail that ftp accounts they have created/updated have been archived/deleted
#
#This script should be executed on the FileZilla server
#
#Requirements:
#- If running as a Scheduled Task (advised), the account executing this script requires "Log on as a Batch Job" permissions on the FileZilla server
#
#- Editing the FileZilla XML:
#  - The user running this script needs NTFS Modify permissions on the "%PROGRAM FILES (x86)%\FileZilla Server\FileZilla Server.xml"
#- Reloading the FileZilla Config
#  - Set-ExecutionPolicy to be set to RemoteSigned (or lower) on the computer running this script and on the FileZilla server (unless you sign the scripts yourself)
#  - The account executing this script requires local admin permissions on the FileZilla server (to execute the /reload-config command)
#- Archiving
#  - The account executing this script requires Modify NTFS permissions on $ftpDataShare to delete old directories
#  - The account executing this script requires Change Share permissions on $ftpDataShare to delete old directories
#  - The account executing this script requires Write NTFS permissions on $ftpDataArchivePath to move old directories
#  - The account executing this script requires Change Share permissions on $ftpDataArchivePath to move old directories
#- Sending e-mail
#  - The user running this script needs to be able to send mail via $smtpServer from the command line (either by relaying or you can add authentication)
#  - The emailUser function assumes that the user's mailAlias is the same as their username, and that it can construct valid e-mail addresses from username@upn
#
#If you like the script, feel free to pop a beer in the post c/o Kev Maitland - I work at the head office of www.sustain.co.uk :)


$filezillaServer = "yourFileZillaServer"
$ftpDataShare = "yourFTPDataShare"
$ftpDataArchivePath = "yourFTPArchiveShare" 
$xmlFilePath = "\\$filezillaServer\FileZillaServer$\FileZilla Server.xml"
$reloadFZConfigCMD = '"C:\Program Files (x86)\FileZilla Server\FileZilla Server.exe" "/reload-config"'
$smtpServer = "yourMailServer
$upn = "@yourdomain.local"
$mailFrom = "ftpserver@yourdomain.local"
$replyTo = "nooneislistening@yourdomain.local"

$daysBeforeDisabling = 30
$daysBeforeArchiving = 90
$warningDaysOffset = 7
[datetime]$date = Get-Date -Format yyyyMMMMdd #Gets Date without Time data

function emailUser([string]$to, [string]$subject, [string]$body){
    $msg = New-Object Net.Mail.MailMessage
    $smtp = New-Object Net.Mail.SmtpClient($smtpServer)
    $msg.From = $mailFrom
    $msg.ReplyTo = $replyTo
    $msg.To.Add("$to$upn")
    $msg.subject = $subject
    $msg.body = $body
    $smtp.Send($msg)
    }

#------------------------------------------
#---Import the FileZilla XML file so that we can examine the accounts
#------------------------------------------
$xml = [xml](Get-Content $xmlFilePath)
 
#------------------------------------------
#---Go through every user and do stuff based on when the account was last updated
#------------------------------------------
foreach ($user in $xml.FileZillaServer.Users.User){ 
    $comments = ($user.SelectSingleNode("Option[@Name='Comments']").InnerText).Split()
    $lastUpdated = get-date $comments[10]
        if ($user.Name -eq "TemplateFTPUser"){Continue}
        Write-Host -ForegroundColor Yellow $user.Name
        Write-Host -ForegroundColor DarkYellow "Last updated "$($date - $lastUpdated).Days" days ago ("$lastUpdated")"
    if ($($date - $lastUpdated).Days -ge $daysBeforeArchiving) {
        Write-Host -ForegroundColor DarkYellow "Archiving..."
        $lastUpdatedBy = $comments[8]
        $userGroup = $user.SelectSingleNode("Option[@Name='Group']").InnerText
        if ($userGroup -eq ""){$userGroup = "None"}
        if (!(Test-Path "$ftpDataArchivePath\$userGroup")){New-Item -ItemType Directory -Path "\\$ftpDataArchivePath\$userGroup"}
        Move-Item "\\$filezillaServer\$ftpDataShare\$userGroup\$($user.Name)" "$ftpDataArchivePath\$userGroup\$($user.Name)" -Force #This assumes that the executing user has write permissions to $archivePath

        $subject = "FTP Account `"$($user.Name)`" has been archived"
        $body = `
"Hello,`n `
The account called $($user.Name) that you created/updated on $(Get-Date $lastUpdated -Format "dd MMMM yy") has been archived. The actual FTP account has been deleted and any files have been moved to the archive area:`n '
    $ftpDataArchivePath\$userGroup\$($user.Name) `n 
If your client needs to transfer you files via secure FTP in the future, you will need to create them a new FTP account using the instructions at:`n `
    http://intranet.sustain.co.uk/ict/SitePages/FTP%20Help.aspx `n `
Love,`n `
The Helpful FTP Robot"
        emailUser -to $lastUpdatedBy -subject $subject -body $body
        $xml.FileZillaServer.Users.RemoveChild($user)
        }
    elseif ($($date - $lastUpdated).Days -ge $daysBeforeDisabling){
        Write-Host -ForegroundColor DarkYellow "Disabling..."
        $user.SelectSingleNode("Option[@Name='Enabled']").InnerText = 0 #This disables the account in FileZilla
        }
    elseif ($($date - $lastUpdated).Days -ge $daysBeforeDisabling-1){
        Write-Host -ForegroundColor DarkYellow "2nd warning..."
        $lastUpdatedBy = $comments[8]
        $subject = "FTP account `"$($user.Name)`" will expire tomorrow"
        $body = `
"Hello,`n `
The account called $($user.Name) that you created/updated on $(Get-Date $lastUpdated -Format "dd MMMM yy") is due to expire on $(Get-Date $date.AddDays(1) -Format "dd MMMM yy"). If you want to pre-empt this, you can reset the password by following the instructions available at: `n `
    http://intranet.sustain.co.uk/ict/SitePages/FTP%20Help.aspx `n `
If you're no longer using the account, you can just ignore this and it will automatically be deactivated tomorrow, and archived on $(Get-Date $date.AddDays($daysBeforeArchiving+1) -Format "dd MMMM yy"), `n `
Love,`n `
The Helpful FTP Robot"
        emailUser -to $lastUpdatedBy -subject $subject -body $body
        }
    elseif ($($date - $lastUpdated).Days -ge $daysBeforeDisabling-$warningDaysOffset){
        Write-Host -ForegroundColor DarkYellow "1st warning..."
        $lastUpdatedBy = $comments[8]
        $subject = "FTP account `"$($user.Name)`" will expire in $warningDaysOffset days"
        $body = `
"Hello,`n `
The account called $($user.Name) that you created/updated on $(Get-Date $lastUpdated -Format "dd MMMM yy") is due to expire on $(Get-Date $date.AddDays($warningDaysOffset) -Format "dd MMMM yy"). If you want to pre-empt this, you can reset the password by following the instructions available at: `n `
    http://intranet.sustain.co.uk/ict/SitePages/FTP%20Help.aspx `n `
If you're no longer using the account, you can just ignore this and it will automatically be deactivated on $(Get-Date $date.AddDays($warningDaysOffset) -Format "dd MMMM yy"), and archived on $(Get-Date $date.AddDays($daysBeforeArchiving+$warningDaysOffset) -Format "dd MMMM yy"), `n `
Love,`n `
The Helpful FTP Robot"
        emailUser -to $lastUpdatedBy -subject $subject -body $body
        }
    else {Write-Host -foregroundcolor Darkyellow "Doing nothing..."}
   }

#------------------------------------------
#---Reload the FileZilla config to initialise the changes
#------------------------------------------
$xml.Save($xmlFilePath)
iex "& $reloadFZConfigCMD"
Edited to improve date evaluation method
Last edited by kevmaitland on 2015-12-07 14:40, edited 2 times in total.

kevmaitland
Contributor
Posts: 8
Joined: 2014-05-13 12:41
First name: Kev
Last name: Maitland

Re: Powershell for users & admins to create & manage FTPacco

#5 Post by kevmaitland » 2014-05-13 13:32

ReloadConfig.ps1

Code: Select all

#Script to reload the FileZilla config from "%PROGRAM FILES (x86)%\FileZilla Server\FileZilla Server.xml" without restarting the services.
#
#This should be saved and executed on the FileZilla Server
#
#Requirements:
#- This command requires local admin permissions on the FileZilla server
#
#If you like the script, feel free to pop a beer in the post c/o Kev Maitland - I work at the head office of www.sustain.co.uk :)

$reloadFZConfigCMD = '"C:\Program Files (x86)\FileZilla Server\FileZilla Server.exe" "/reload-config"'
iex "& $reloadFZConfigCMD"
Exit-PSSession #This automatically drops the PSSession, which reduces the possibility of abuse as the -RunAsCredentials account.

kevmaitland
Contributor
Posts: 8
Joined: 2014-05-13 12:41
First name: Kev
Last name: Maitland

Re: Powershell for users & admins to create & manage FTPacco

#6 Post by kevmaitland » 2014-05-13 13:34

setPsSessionConfigurationForFZAdmin.ps1

Code: Select all

#Script to configure a PSSessionConfiguration to allow remote users to run the /reload-config command locally on the FileZilla server
#When this script is run, the end-users who will be modifying FileZilla accounts need to be granted Execute(Invoke) permissions. These can be restricted by using a specific Security Group, or can be granted generally by adding the "Domain Users" Security Group
#This alleviates the need for end-users to be local administrators on the FileZilla server by granting them elevated privileges in a restricted way
#
#This should be executed once on the FileZilla Server (and run again whenever the $filezillaServerLocalAdmin password changes)
#
#Requirements:
#- The RunAsCredential account needs to be a local administrator (otherwise the /reload-config command will fail)
#- The password needs to be provided in Plain Text here
#- The $psSessionConfigurationNameOnFileZillaServer value should match the value used in the NewUser / ResetUser scripts
#
#If you like the script, feel free to pop a beer in the post c/o Kev Maitland - I work at the head office of www.sustain.co.uk :)


$filezillaServer = "yourFileZillaServer"
$filezillaServerLocalAdmin = "yourDedicatedLocalAdminAccountForFileZilla"
$filezillaServerLocalAdminPlainTextPassword = 'yourNiceLongSecurePassword'
$pathToReloadConfigScript = "C:\Program Files (x86)\FileZilla Server\"
$reloadConfigScriptName = "ReloadConfig.ps1"
$psSessionConfigurationNameOnFileZillaServer = "FileZilla"



Set-PSSessionConfiguration -Name $psSessionConfigurationNameOnFileZillaServer -ApplicationBase $pathToReloadConfigScript -RunAsCredential $(New-Object -TypeName System.Management.Automation.PSCredential "$filezillaServer\$filezillaServerLocalAdmin", $(ConvertTo-SecureString -String $filezillaServerLocalAdminPlainTextPassword -AsPlainText -Force)) -ShowSecurityDescriptorUI -StartupScript "$pathToReloadConfigScript\$reloadConfigScriptName"

User avatar
botg
Site Admin
Posts: 35564
Joined: 2004-02-23 20:49
First name: Tim
Last name: Kosse

Re: Powershell for users & admins to create & manage FTPacco

#7 Post by botg » 2014-05-14 05:54

Nice.

User avatar
boco
Contributor
Posts: 26938
Joined: 2006-05-01 03:28
Location: Germany

Re: Powershell for users & admins to create & manage FTPacco

#8 Post by boco » 2014-05-14 20:22

@botg: Thoughts about a Contributor rank?
No support requests over PM! You will NOT get any reply!!!
FTP connection problems? Please read Network Configuration.
FileZilla connection test: https://filezilla-project.org/conntest.php
FileZilla Pro support: https://customerforum.fileZilla-project.org

User avatar
botg
Site Admin
Posts: 35564
Joined: 2004-02-23 20:49
First name: Tim
Last name: Kosse

Re: Powershell for users & admins to create & manage FTPacco

#9 Post by botg » 2014-05-17 06:40

There is now :)

Post Reply