├── ShareFileSnapIn ├── ShareFile.psm1 ├── Assets │ ├── sf-icon.ico │ ├── branding.jpg │ └── Citrix EULA.txt ├── Add-ShareFile-SnapIn.ps1 ├── Parallel │ ├── ActionType.cs │ ├── IAction.cs │ ├── ProgressInfo.cs │ ├── Utility.cs │ ├── DownloadAction.cs │ ├── UploadAction.cs │ └── ActionManager.cs ├── Constants.cs ├── NewItemParameters.cs ├── NLog.config ├── ShareFileDriveParameters.cs ├── packages.config ├── ShareFileDriveInfo.cs ├── Browser │ ├── BasicAuthDialog.cs │ ├── OAuthAuthenticationForm.Designer.cs │ ├── BasicAuthDialog.resx │ ├── OAuthAuthenticationForm.resx │ ├── OAuthAuthenticationForm.cs │ └── BasicAuthDialog.Designer.cs ├── GetSfClient.cs ├── app.config ├── Extensions │ └── TaskHelper.cs ├── LICENSE.txt ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── ShareFile.Format.ps1xml ├── OAuthToken.cs ├── Resume │ ├── ProgressFile.cs │ ├── SupportHandler.cs │ └── ResumeSupport.cs ├── NewSfClient.cs ├── Log │ └── Logger.cs ├── ShareFilePSSnapIn.cs ├── WebpopInternetExplorerMode.cs └── AuthenticationDomain.cs ├── Samples ├── Images │ ├── Agreement.png │ ├── Download.png │ ├── SyncingFiles.png │ ├── GettingStarted.png │ ├── SampleScripts.png │ ├── ScheduleScript.png │ └── SystemRequirements.png ├── Monitor_Uploads_From_ShareFile_Queue_SYMC_DLP_INSTRUCTIONS_1.1.docx ├── FindUsersByCompany.ps1 ├── DeleteUsers.ps1 ├── CreateUsers.ps1 ├── DownloadFiles.ps1 ├── UploadLocalFiles.ps1 ├── RemoveRole.ps1 ├── UpdateRoles.ps1 ├── DisabledUsers.ps1 ├── ExpireFileBox.ps1 ├── AutoArchiveFiles.ps1 ├── DeleteMostRecent.ps1 ├── DownloadFileBasedOnShareID.ps1 ├── DownloadScript.ps1 ├── StorageReport.ps1 ├── BackupShareFileAccount.ps1 └── Monitor_Uploads_From_ShareFile_Queue_SYMC_DLP.ps1 ├── ShareFileSnapIn-Installer-x32 ├── Globals.wxi ├── ShareFileSnapIn-Installer-x32.wixproj └── Product.wxs ├── ShareFileSnapIn-Installer-x64 ├── Globals.wxi ├── ShareFileSnapIn-Installer-x64.wixproj └── Product.wxs ├── Test-ShareFileSnapIn ├── app.config ├── NLog.config ├── Properties │ └── AssemblyInfo.cs ├── LoginTests.cs ├── MapDriveTests.cs ├── Utils.cs ├── Test-ShareFileSnapIn.csproj ├── CopySFItemsTests.cs └── OrderedTests.orderedtest ├── .gitignore └── README.md /ShareFileSnapIn/ShareFile.psm1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Samples/Images/Agreement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharefile-org/ShareFile-PowerShell/HEAD/Samples/Images/Agreement.png -------------------------------------------------------------------------------- /Samples/Images/Download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharefile-org/ShareFile-PowerShell/HEAD/Samples/Images/Download.png -------------------------------------------------------------------------------- /Samples/Images/SyncingFiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharefile-org/ShareFile-PowerShell/HEAD/Samples/Images/SyncingFiles.png -------------------------------------------------------------------------------- /Samples/Images/GettingStarted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharefile-org/ShareFile-PowerShell/HEAD/Samples/Images/GettingStarted.png -------------------------------------------------------------------------------- /Samples/Images/SampleScripts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharefile-org/ShareFile-PowerShell/HEAD/Samples/Images/SampleScripts.png -------------------------------------------------------------------------------- /Samples/Images/ScheduleScript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharefile-org/ShareFile-PowerShell/HEAD/Samples/Images/ScheduleScript.png -------------------------------------------------------------------------------- /ShareFileSnapIn/Assets/sf-icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharefile-org/ShareFile-PowerShell/HEAD/ShareFileSnapIn/Assets/sf-icon.ico -------------------------------------------------------------------------------- /ShareFileSnapIn/Assets/branding.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharefile-org/ShareFile-PowerShell/HEAD/ShareFileSnapIn/Assets/branding.jpg -------------------------------------------------------------------------------- /Samples/Images/SystemRequirements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharefile-org/ShareFile-PowerShell/HEAD/Samples/Images/SystemRequirements.png -------------------------------------------------------------------------------- /ShareFileSnapIn/Assets/Citrix EULA.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharefile-org/ShareFile-PowerShell/HEAD/ShareFileSnapIn/Assets/Citrix EULA.txt -------------------------------------------------------------------------------- /ShareFileSnapIn/Add-ShareFile-SnapIn.ps1: -------------------------------------------------------------------------------- 1 | $Host.UI.RawUI.BackgroundColor = 'DarkCyan' 2 | $Host.UI.RawUI.ForegroundColor = 'Yellow' 3 | cd $env:USERPROFILE 4 | cls 5 | Add-PSSnapIn ShareFile -------------------------------------------------------------------------------- /Samples/Monitor_Uploads_From_ShareFile_Queue_SYMC_DLP_INSTRUCTIONS_1.1.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharefile-org/ShareFile-PowerShell/HEAD/Samples/Monitor_Uploads_From_ShareFile_Queue_SYMC_DLP_INSTRUCTIONS_1.1.docx -------------------------------------------------------------------------------- /ShareFileSnapIn/Parallel/ActionType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ShareFile.Api.Powershell.Parallel 8 | { 9 | enum ActionType 10 | { 11 | Force, 12 | Sync, 13 | None 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ShareFileSnapIn-Installer-x32/Globals.wxi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ShareFileSnapIn-Installer-x64/Globals.wxi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Test-ShareFileSnapIn/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace ShareFile.Api.Powershell 2 | { 3 | // https://msdn.microsoft.com/en-us/library/ee330730(v=vs.85).aspx#browser_emulation 4 | public enum InternetExplorerVersion 5 | { 6 | None, 7 | IE7 = 7000, 8 | IE8 = 8000, 9 | IE8_Standards = 8888, 10 | IE9 = 9000, 11 | IE9_Standards = 9999, 12 | IE10 = 10000, 13 | IE10_Standards = 10001, 14 | IE11 = 11000, 15 | IE11_Edge = 11001, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ShareFileSnapIn/NewItemParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Management.Automation; 3 | 4 | namespace ShareFile.Api.Powershell 5 | { 6 | public class NewItemParameters 7 | { 8 | public NewItemParameters() 9 | { 10 | Uri = null; 11 | Details = null; 12 | } 13 | 14 | [Parameter(Mandatory = false)] 15 | public Uri Uri { get; set; } 16 | 17 | [Parameter(Mandatory = false)] 18 | public string Details { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ShareFileSnapIn/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Test-ShareFileSnapIn/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #ignore thumbnails created by windows 3 | Thumbs.db 4 | #Ignore files build by Visual Studio 5 | *.obj 6 | *.pdb 7 | *.user 8 | *.aps 9 | *.pch 10 | *.vspscc 11 | *_i.c 12 | *_p.c 13 | *.ncb 14 | *.suo 15 | *.tlb 16 | *.tlh 17 | *.bak 18 | *.cache 19 | *.ilk 20 | *.log 21 | [Dd]ebug*/ 22 | *.lib 23 | *.sbr 24 | obj/ 25 | _ReSharper*/ 26 | [Tt]est[Rr]esult* 27 | *.InstallLog 28 | *.InstallState 29 | 30 | TestClient/*.user 31 | TestClient/bin 32 | TestClient/obj 33 | packages/* 34 | Build/runbuild.txt 35 | docs/* 36 | 37 | */bin 38 | */obj 39 | */.vs 40 | /.vs 41 | -------------------------------------------------------------------------------- /ShareFileSnapIn/ShareFileDriveParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Management.Automation; 3 | 4 | namespace ShareFile.Api.Powershell 5 | { 6 | public class ShareFileDriveParameters 7 | { 8 | public ShareFileDriveParameters() 9 | { 10 | Client = null; 11 | RootUri = null; 12 | } 13 | 14 | [Parameter(Mandatory=true)] 15 | public PSShareFileClient Client { get; set; } 16 | 17 | [Parameter(Mandatory = false)] 18 | public Uri RootUri { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ShareFileSnapIn/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Parallel/IAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ShareFile.Api.Powershell.Parallel 8 | { 9 | /// 10 | /// IAction Interface 11 | /// 12 | interface IAction 13 | { 14 | /// 15 | /// Copy File Item method to upload/download files 16 | /// 17 | void CopyFileItem(ProgressInfo progressInfo); 18 | ActionType OpActionType { get; set; } 19 | string FileName { get; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Parallel/ProgressInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ShareFile.Api.Powershell.Parallel 8 | { 9 | class ProgressInfo 10 | { 11 | public int FileIndex { get; set; } 12 | public ProgressDoneDelegate ProgressTransferred { get; set; } 13 | public ProgressTotalDelegate ProgressTotal { get; set; } 14 | public long Transferred { get; set; } 15 | public long Total { get; set; } 16 | public bool Completed { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ShareFileSnapIn/ShareFileDriveInfo.cs: -------------------------------------------------------------------------------- 1 | using ShareFile.Api.Client; 2 | using ShareFile.Api.Client.Models; 3 | using System; 4 | using System.Management.Automation; 5 | 6 | namespace ShareFile.Api.Powershell 7 | { 8 | public class ShareFileDriveInfo : PSDriveInfo 9 | { 10 | public ShareFileClient Client { get; private set; } 11 | 12 | public Uri RootUri { get; set; } 13 | 14 | public Item RootItem { get; set; } 15 | 16 | public ShareFileDriveInfo(PSDriveInfo driveInfo, ShareFileDriveParameters driveParams) 17 | : base( driveInfo ) 18 | { 19 | Client = driveParams.Client.Client; 20 | RootUri = driveParams.RootUri; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Samples/FindUsersByCompany.ps1: -------------------------------------------------------------------------------- 1 | Param ( [string]$companyName ) 2 | 3 | #Get all users by companyName 4 | Add-PSSnapIn ShareFile 5 | $sfClient = New-SfClient 6 | 7 | #Pull all of the Account Employees or Clients 8 | $sfUsers = Send-SfRequest -Client $sfClient -Entity Accounts\Employees 9 | 10 | $fileOutput = @() 11 | #Loop through each of the users 12 | foreach($sfUserId in $sfUsers) { 13 | #Get full user information including security 14 | $sfUser = Send-SfRequest -Client $sfClient -Entity Users -Id $sfUserId.Id 15 | if ($sfUser.Company -eq $companyName) { 16 | $fileOutput += New-Object PSObject -Property @{'UserId'=$sfUserId.Id;'FullName'=$sfUser.FullName;'Email'=$sfUser.Email;'Company'=$sfUser.Company} 17 | } 18 | } 19 | #output the results 20 | $fileOutput 21 | -------------------------------------------------------------------------------- /Samples/DeleteUsers.ps1: -------------------------------------------------------------------------------- 1 | #Script to delete users found by the Disabled Users script 2 | 3 | 4 | Function DeleteUsers{ 5 | Param ([Parameter(HelpMessage="Hi Keith")] [string]$UserType="employee") 6 | $client = New-SfClient -Name "c:\tmp\sfclient.sfps" 7 | $admin_userid = "ADMIN_USERID" 8 | 9 | $sfUserObjects = Import-Csv ("C:\tmp\" + $UserType + ".csv") 10 | 11 | foreach($sfUser in $sfUserObjects){ 12 | Send-SfRequest -Client $client -Method Delete -Entity Users -Id $sfUser.UserId -Parameters @{"completely" = "true"; "itemsReassignTo" = $admin_userid; "groupsReassignTo" = $admin_userid} 13 | } 14 | 15 | } 16 | 17 | #New-SfClient -Name "c:\tmp\sfclient.sfps" 18 | Add-PSSnapin ShareFile 19 | DeleteUsers -UserType "employee"; 20 | DeleteUsers -UserType "client"; 21 | -------------------------------------------------------------------------------- /Samples/CreateUsers.ps1: -------------------------------------------------------------------------------- 1 | Add-PSSnapin ShareFile 2 | $sfClient = New-SfClient 3 | 4 | #The import file would typically be an exported contact list from Outlook or equivalent 5 | $contacts = Import-Csv .\Contacts.CSV 6 | foreach ($contact in $contacts) 7 | { 8 | #make sure we have an email, name, and company 9 | if ($contact.'E-mail Address' -and $contact.'First Name' -and $contact.'Last Name') 10 | { 11 | #create contact in ShareFile 12 | $user = New-Object ShareFile.Api.Client.Models.User 13 | 14 | #required fields 15 | $user.FirstName = $contact.'First Name' 16 | $user.LastName = $contact.'Last Name' 17 | $user.Email = $contact.'E-mail Address' 18 | 19 | #optional fields 20 | $user.Company = $contact.Company 21 | 22 | #create client user 23 | Send-SfRequest $sfClient -Method POST -Entity Users -Body $user -Parameters @{"addshared" = "true"} 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Browser/BasicAuthDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace ShareFile.Api.Powershell.Browser 12 | { 13 | public partial class BasicAuthDialog : Form 14 | { 15 | public string Username { get { return textBoxUsername.Text; } } 16 | 17 | public string Password { get { return textBoxPassword.Text; } } 18 | 19 | public BasicAuthDialog(string domain) 20 | { 21 | InitializeComponent(); 22 | labelDomainName.Text = domain; 23 | } 24 | 25 | private void buttonOK_Click(object sender, EventArgs e) 26 | { 27 | Close(); 28 | } 29 | 30 | private void buttonCancel_Click(object sender, EventArgs e) 31 | { 32 | Close(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ShareFileSnapIn/GetSfClient.cs: -------------------------------------------------------------------------------- 1 | using ShareFile.Api.Client.Exceptions; 2 | using System.Management.Automation; 3 | 4 | namespace ShareFile.Api.Powershell 5 | { 6 | [Cmdlet(VerbsCommon.Get, Noun)] 7 | public class GetSfClient : PSCmdlet 8 | { 9 | private const string Noun = "SfClient"; 10 | 11 | [Parameter(Position=0)] 12 | public string Name { get; set; } 13 | 14 | protected override void ProcessRecord() 15 | { 16 | if (Name.IndexOf('.') < 0) Name += ".sfps"; 17 | var psc = new PSShareFileClient(Name); 18 | psc.Load(); 19 | try 20 | { 21 | psc.Client.Sessions.Get().Execute(); 22 | } 23 | catch (WebAuthenticationException) 24 | { 25 | psc = new PSShareFileClient(Name); 26 | psc.Load(); 27 | psc.Client.Sessions.Get().Execute(); 28 | } 29 | WriteObject(psc); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ShareFileSnapIn/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Extensions/TaskHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using System.Windows.Threading; 3 | 4 | namespace ShareFile.Api.Powershell.Extensions 5 | { 6 | public static class TaskHelper 7 | { 8 | public static void RunSynchronously(this Task task) 9 | { 10 | var frame = new DispatcherFrame(); 11 | using (task) 12 | { 13 | task.ContinueWith(t => frame.Continue = false); 14 | 15 | frame.Continue = true; 16 | Dispatcher.PushFrame(frame); 17 | 18 | if (task.Exception != null) 19 | { 20 | throw task.Exception; 21 | } 22 | } 23 | } 24 | 25 | public static T RunSynchronously(Task task) 26 | { 27 | var frame = new DispatcherFrame(); 28 | using (task) 29 | { 30 | task.ContinueWith(t => frame.Continue = false); 31 | 32 | frame.Continue = true; 33 | Dispatcher.PushFrame(frame); 34 | return task.Result; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ShareFileSnapIn/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016, Citrix Systems, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Samples/DownloadFiles.ps1: -------------------------------------------------------------------------------- 1 | Add-PSSnapin ShareFile 2 | 3 | ################################################################################ 4 | # DownloadFiles.ps1 5 | # 6 | # This script will download all files from the My Files and Folders area of 7 | # ShareFile to the local Documents directory. 8 | # 9 | 10 | #Run the following interactively to create a login token that can be used by Get-SfClient in unattended scripts 11 | #$sfClient = New-SfClient -Name ((Join-Path $env:USERPROFILE "Documents") + "\YourSubdomain.sfps") -Account YourSubdomain 12 | $sfClient = Get-SfClient -Name ((Join-Path $env:USERPROFILE "Documents") + "\YourSubdomain.sfps") 13 | 14 | #ShareFile directory is relative to the root of the account 15 | #get the current user's home folder to use as the starting point 16 | $ShareFileHomeFolder = "sfdrive:/" + (Send-SfRequest $sfClient -Entity Items).Name 17 | 18 | #use the local My Documents folder 19 | $LocalPath = (Join-Path $env:USERPROFILE "Documents") 20 | 21 | #Create a PowerShell provider for ShareFile at the location specified 22 | New-PSDrive -Name sfDrive -PSProvider ShareFile -Client $sfClient -Root "/" 23 | 24 | #download files from a sub-folder in ShareFile to a local folder 25 | #path must be specified (can't use root) so make sure to map the provider at a level higher than you want to copy from 26 | Copy-SfItem -Path $ShareFileHomeFolder -Destination $LocalPath 27 | 28 | #Remove the PSProvider when we are done 29 | Remove-PSDrive sfdrive 30 | -------------------------------------------------------------------------------- /Test-ShareFileSnapIn/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Test-ShareFileSnapIn")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Test-ShareFileSnapIn")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("84694bd1-3091-4597-8421-ebba4b986737")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ShareFileSnapIn")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ShareFileSnapIn")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("d0e3f40a-07b1-44bb-b788-e05d460e371a")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.*")] 36 | // [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Samples/UploadLocalFiles.ps1: -------------------------------------------------------------------------------- 1 | Add-PSSnapin ShareFile 2 | 3 | ################################################################################ 4 | # UploadLocalFiles.ps1 5 | # 6 | # This script will upload all files in the local Documents directory to the 7 | # My Files and Folders area of ShareFile. 8 | # 9 | # Note: The ShareFile location needs to be specified as files cannot be written 10 | # to the root of the account. This script gets the user's home folder and 11 | # uses that, but shared folders could also be used. 12 | # 13 | 14 | #Run the following interactively to create a login token that can be used by Get-SfClient in unattended scripts 15 | #$sfClient = New-SfClient -Name ((Join-Path $env:USERPROFILE "Documents") + "\YourSubdomain.sfps") -Account YourSubdomain 16 | $sfClient = Get-SfClient -Name ((Join-Path $env:USERPROFILE "Documents") + "\YourSubdomain.sfps") 17 | 18 | 19 | #upload directory is relative to the root of the account 20 | #get the current user's home folder to use as the starting point 21 | $ShareFileHomeFolder = (Send-SfRequest $sfClient -Entity Items).Url 22 | 23 | #use the local My Documents folder as source 24 | $LocalPath = (Join-Path $env:USERPROFILE "Documents") 25 | 26 | #Create a PowerShell provider for ShareFile at the location specified 27 | New-PSDrive -Name sfDrive -PSProvider ShareFile -Client $sfClient -Root "\" -RootUri $ShareFilePath 28 | 29 | #upload all the files (recursively) in the local folder to the specified folder in ShareFile 30 | Copy-SfItem -Path $LocalPath -Destination "sfDrive:" 31 | 32 | #Remove the PSProvider when we are done 33 | Remove-PSDrive sfdrive 34 | -------------------------------------------------------------------------------- /ShareFileSnapIn/ShareFile.Format.ps1xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FolderTableView 6 | 7 | ShareFile.Api.Client.Models.Item 8 | 9 | 10 | 11 | 12 | 40 13 | 14 | 15 | 32 16 | 17 | 18 | 15 19 | 20 | 21 | 15 22 | 23 | 24 | 25 | 26 | 27 | 28 | Id 29 | 30 | 31 | FileName 32 | 33 | 34 | FileCount 35 | 36 | 37 | FileSizeInKB 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ShareFileSnapIn/OAuthToken.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace ShareFile.Api.Powershell 4 | { 5 | public class OAuthToken 6 | { 7 | [JsonProperty(PropertyName = "access_token")] 8 | public string AccessToken { get; set; } 9 | 10 | [JsonProperty(PropertyName = "refresh_token")] 11 | public string RefreshToken { get; set; } 12 | 13 | [JsonProperty(PropertyName = "token_type")] 14 | public string TokenType { get; set; } 15 | 16 | [JsonProperty(PropertyName = "appcp")] 17 | public string AppCP { get; set; } 18 | 19 | [JsonProperty(PropertyName = "apicp")] 20 | public string ApiCP { get; set; } 21 | 22 | [JsonProperty(PropertyName = "subdomain")] 23 | public string Subdomain { get; set; } 24 | 25 | [JsonProperty(PropertyName = "expires_in")] 26 | public long ExpiresIn { get; set; } 27 | 28 | [JsonProperty(PropertyName = "access_files_folders")] 29 | public bool AccessFilesFolders { get; set; } 30 | 31 | [JsonProperty(PropertyName = "modify_files_folders")] 32 | public bool ModifyFilesFolders { get; set; } 33 | 34 | [JsonProperty(PropertyName = "admin_users")] 35 | public bool AdminUsers { get; set; } 36 | 37 | [JsonProperty(PropertyName = "admin_accounts")] 38 | public bool AdminAccounts { get; set; } 39 | 40 | [JsonProperty(PropertyName = "change_my_settings")] 41 | public bool ChangeMySettings { get; set; } 42 | 43 | [JsonProperty(PropertyName = "web_app_login")] 44 | public bool WebAppLogin { get; set; } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Samples/RemoveRole.ps1: -------------------------------------------------------------------------------- 1 | Add-PSSnapin ShareFile 2 | 3 | ################################################################################ 4 | # RemoveRole.ps1 5 | # 6 | # This script will update a user's roles to remove a specified list of roles. 7 | # 8 | 9 | #Run the following interactively to create a login token that can be used by Get-SfClient in unattended scripts 10 | #$sfClient = New-SfClient -Name ((Join-Path $env:USERPROFILE "Documents") + "\YourSubdomain.sfps") -Account YourSubdomain 11 | $sfClient = Get-SfClient -Name ((Join-Path $env:USERPROFILE "Documents") + "\YourSubdomain.sfps") 12 | 13 | #get a user by email address 14 | $user = Send-SfRequest -Client $sfClient -Method GET -Entity Users -Parameters @{"emailaddress" = "sample@email.com"} 15 | 16 | #Build up a JSON string with all roles we want 17 | $JSONBody = '{"Roles" : [' 18 | 19 | #list of roles we want to KEEP 20 | $RolesToKeep = @("CanChangePassword", "CanUseFileBox") 21 | 22 | #save which roles the user currently belongs to except for the one we want to remove 23 | $index=0 24 | foreach ($role in $user.roles) 25 | { 26 | #don't capture the role if we want to remove it 27 | if ($role.Value -notin $RolesToKeep) 28 | { 29 | #need to append a comma if more than 1 item in list and not last item 30 | if ($index -eq ($user.Roles.Count - 1)) 31 | { $JSONBody += ('"' + $role.Value + '"') } 32 | else 33 | { $JSONBody += ('"' + $role.Value + '",') } 34 | } 35 | $index++ 36 | } 37 | 38 | #close the JSON 39 | $JSONBody += ']}' 40 | 41 | #Overwrite the roles with this list 42 | Send-SfRequest -Client $sfClient -Method PUT -Entity Users -Navigation Roles -Id $user.Id -BodyText $JSONBody 43 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Resume/ProgressFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Xml.Serialization; 7 | 8 | namespace ShareFile.Api.Powershell.Resume 9 | { 10 | /// 11 | /// ProgressFile Serializable class 12 | /// Its image will be saved in file 13 | /// 14 | [XmlRootAttribute("ProgressFile", Namespace = "", IsNullable = false)] 15 | public class ProgressFile 16 | { 17 | public ProgressFile() 18 | { 19 | 20 | } 21 | 22 | /// 23 | /// 24 | /// 25 | [XmlArray("ArgumentSource"), XmlArrayItem("Path", typeof(string))] 26 | public string[] ArgumentSource = new String[]{}; 27 | 28 | /// 29 | /// 30 | /// 31 | public string ArgumentTarget; 32 | 33 | /// 34 | /// 35 | /// 36 | public bool ArgumentForce; 37 | 38 | /// 39 | /// 40 | /// 41 | public string ArgumentDetails; 42 | 43 | /// 44 | /// 45 | /// 46 | [XmlIgnore] 47 | public bool IsExist; 48 | 49 | /// 50 | /// 51 | /// 52 | public bool IsPending; 53 | 54 | /// 55 | /// 56 | /// 57 | [XmlArray("CompletedFiles"), XmlArrayItem("File", typeof(string))] 58 | public System.Collections.ArrayList CompletedFiles = new System.Collections.ArrayList(); 59 | 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Samples/UpdateRoles.ps1: -------------------------------------------------------------------------------- 1 | Add-PSSnapin ShareFile 2 | 3 | ################################################################################ 4 | # UpdateRoles.ps1 5 | # 6 | # This script will update the roles for a specified user by email address. 7 | # 8 | 9 | #Run the following interactively to create a login token that can be used by Get-SfClient in unattended scripts 10 | #$sfClient = New-SfClient -Name ((Join-Path $env:USERPROFILE "Documents") + "\YourSubdomain.sfps") -Account YourSubdomain 11 | $sfClient = Get-SfClient -Name ((Join-Path $env:USERPROFILE "Documents") + "\YourSubdomain.sfps") 12 | 13 | 14 | #get a user by email address 15 | $user = Send-SfRequest -Client $sfClient -Method GET -Entity Users -Parameters @{"emailaddress" = "sample@email.com"} 16 | 17 | #update user roles to add all permissions 18 | Send-SfRequest -Client $sfClient -Method PATCH -Entity Users -Navigation Roles -Id $user.Id -BodyText ' 19 | { "Roles" : [ 20 | "CanChangePassword", 21 | "CanManageMySettings", 22 | "CanUseFileBox", 23 | "CanManageUsers", 24 | "CanCreateFolders", 25 | "CanUseDropBox", 26 | "CanSelectFolderZone", 27 | "CreateNetworkShareConnectors", 28 | "CreateSharePointConnectors", 29 | "AdminAccountPolicies", 30 | "AdminBilling", 31 | "AdminBranding", 32 | "AdminChangePlan", 33 | "AdminFileBoxAccess", 34 | "AdminManageEmployees", 35 | "AdminRemoteUploadForms", 36 | "AdminReporting", 37 | "AdminSharedDistGroups", 38 | "AdminSharedAddressBook", 39 | "AdminViewReceipts", 40 | "AdminDelegate", 41 | "AdminManageFolderTemplates", 42 | "AdminEmailMessages", 43 | "AdminSSO", 44 | "AdminSuperGroup", 45 | "AdminZones", 46 | "AdminCreateSharedGroups", 47 | "AdminConnectors" 48 | ]}' 49 | -------------------------------------------------------------------------------- /Samples/DisabledUsers.ps1: -------------------------------------------------------------------------------- 1 | #Get all disabled users 2 | 3 | Add-PSSnapIn ShareFile 4 | 5 | Function FindDisabledUsers{ 6 | Param ( [string]$UserType="employee") 7 | $client = Get-SfClient -Name "c:\tmp\sfclient.sfps" 8 | $entity = ""; 9 | switch ($UserType.ToLower()){ 10 | "employee"{ 11 | $entity = 'Accounts/Employees'; 12 | } 13 | "client" { 14 | $entity = 'Accounts/Clients'; 15 | } 16 | } 17 | #Pull all of the Account Employees or Clients 18 | $sfUsers = Send-SfRequest -Client $client -Entity $entity 19 | 20 | $fileOutput = @() 21 | #Loop through each of the Employees or Clients returned from inital call 22 | foreach($sfUserId in $sfUsers){ 23 | #Get full user information including security 24 | $sfUser = Send-SfRequest -Client $client -Entity Users -Id $sfUserId.Id -Expand Security 25 | #Output to Console Emails of disabled users 26 | Write-Host $sfUser.Email 27 | #check to see if security parameter IsDisabled is true 28 | switch ($sfUser.Security.IsDisabled ) { 29 | "True" { 30 | $fileOutput += New-Object PSObject -Property @{'UserId'=$sfUserId.Id;'FullName'=$sfUser.FullName;'Email'=$sfUser.Email} 31 | } 32 | } 33 | } 34 | 35 | #Output CSV file with all disabled user information 36 | $fileOutput | Export-Csv ("C:\tmp\" + $UserType + ".csv") -Force -NoTypeInformation 37 | } 38 | 39 | #Comment out this line after the first run in order to use the saved authentication file 40 | New-SfClient -Name "c:\tmp\sfclient.sfps" 41 | #Get-SfClient -Name "c:\tmp\sfclient.sfps" 42 | 43 | FindDisabledUsers -UserType "employee"; 44 | FindDisabledUsers -UserType "client"; 45 | -------------------------------------------------------------------------------- /ShareFileSnapIn/NewSfClient.cs: -------------------------------------------------------------------------------- 1 | using ShareFile.Api.Powershell.Properties; 2 | using System.Management.Automation; 3 | 4 | namespace ShareFile.Api.Powershell 5 | { 6 | [Cmdlet(VerbsCommon.New, Noun)] 7 | public class NewSfClient : PSCmdlet 8 | { 9 | private const string Noun = "SfClient"; 10 | 11 | [Parameter(Position = 0)] 12 | public string Name { get; set; } 13 | 14 | [Parameter(Position = 1)] 15 | public string Account { get; set; } 16 | 17 | [Parameter(Position = 2)] 18 | public string Domain { get; set; } 19 | 20 | [Parameter] 21 | public PSCredential Credential { get; set; } 22 | 23 | [Parameter] 24 | public string ApiVersion { get; set; } 25 | 26 | [Parameter] 27 | public string Provider { get; set; } 28 | 29 | [Parameter] 30 | public string Email { get; set; } 31 | 32 | protected override void ProcessRecord() 33 | { 34 | if (ApiVersion == null) ApiVersion = Resources.DefaultApiVersion; 35 | if (Domain == null) Domain = Resources.DefaultApiDomain; 36 | if (Account == null) Account = Resources.DefaultGlobalApiSubdomain; 37 | if (Provider == null) Provider = Resources.ShareFileProvider; 38 | var authDomain = new AuthenticationDomain() 39 | { 40 | Account = Account, 41 | Domain = Domain, 42 | ApiVersion = ApiVersion, 43 | Provider = Provider, 44 | Username = Email 45 | }; 46 | authDomain.Credential = Credential != null ? Credential.GetNetworkCredential() : null; 47 | PSShareFileClient psc = new PSShareFileClient(Name, authDomain); 48 | psc.GetSession(); 49 | WriteObject(psc); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Log/Logger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using NLog; 8 | using NLog.Config; 9 | using NLog.Targets; 10 | using ShareFile.Api.Powershell.Properties; 11 | 12 | namespace ShareFile.Api.Powershell.Log 13 | { 14 | /// 15 | /// ShareFile Logger class to log messages using NLog logger 16 | /// Logger.Instance property to retrieve the NLog.Logger instance 17 | /// Logger file name is specified in Resources files 18 | /// Logger is configured in NLog.config file 19 | /// 20 | class Logger 21 | { 22 | /// 23 | /// Configure & Return the NLog.Logger object 24 | /// 25 | public static NLog.Logger Instance 26 | { 27 | get 28 | { 29 | // if LogManager failed to configure automatically then configure it manually by specifying the paths 30 | // (due to path issues (as assemble path is different & current location is different) it will not configure automatically) 31 | if (LogManager.Configuration == null) 32 | { 33 | String targetName = "logfile"; 34 | String directory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); 35 | LogManager.Configuration = new XmlLoggingConfiguration(Path.Combine(directory, Resources.LogConfigFile)); 36 | 37 | directory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 38 | var fileTarget = LogManager.Configuration.FindTargetByName(targetName) as FileTarget; 39 | fileTarget.FileName = Path.Combine(directory, Resources.AppName, Resources.LogFile); 40 | } 41 | 42 | return LogManager.GetCurrentClassLogger(); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Samples/ExpireFileBox.ps1: -------------------------------------------------------------------------------- 1 | Add-PSSnapin ShareFile 2 | 3 | ################################################################################ 4 | # ExpireFileBox.ps1 5 | # 6 | # This script will list all files that are in any user's filebox and are 7 | # over 7 days old. By default the file box holds files for 30 days but 8 | # with this script you could identify and delete items earlier. Just uncomment 9 | # the line that processes the delete once you have verified the files. 10 | # 11 | # Notes: 12 | # - The Outlook plug-in also uses file box to store files shared. Deleting 13 | # these files will expire the shared links. 14 | # - This script should be run as an administrator who has the ability to view 15 | # other user's filebox 16 | # - 17 | # 18 | 19 | #Run the following interactively to create a login token that can be used by Get-SfClient in unattended scripts 20 | #$sfClient = New-SfClient -Name "C:\Users\Peter\Documents\YourSubdomain.sfps" -Account YourSubdomain 21 | $sfClient = Get-SfClient -Name "C:\Users\Peter\Documents\YourSubdomain.sfps" 22 | 23 | #Get all the employee users on the account 24 | $employees = Send-SfRequest $sfClient -Method GET -Entity Accounts/Employees -select "Id,Name,Email" 25 | foreach ($employee in $employees) 26 | { 27 | $FileBoxID = "Users(" + $employee.Id + ")/FileBox" 28 | $FileBoxFolder = Send-SfRequest $sfClient -Method GET -Entity $FileBoxID -Expand Children 29 | 30 | #list the employee name 31 | Write-Host ("Employee:`t{0} ({1})" -f $employee.Name, $employee.Email) 32 | foreach ($file in $FileBoxFolder.Children) 33 | { 34 | #Check if the date the file was more than xx days ago 35 | if ( ($file.CreationDate.AddDays($FileBoxExpiration)) -le (Get-Date) ) 36 | { 37 | Write-Host ("Deleting File:`t{0}`t`t{1}" -f $file.Name, $file.CreationDate) 38 | #BELOW LINE IS COMMENTED OUT FOR SAFETY - THIS DOES THE ACTUAL DELETE 39 | #Send-SfRequest $sfClient -Method DELETE -Entity Items -Id $file.Id 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Test-ShareFileSnapIn/LoginTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.IO; 4 | using System.Management.Automation; 5 | using System.Management.Automation.Runspaces; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | using ShareFile.Api.Powershell; 8 | 9 | namespace Test_ShareFileSnapIn 10 | { 11 | [TestClass] 12 | public class LoginTests 13 | { 14 | private Runspace runspace = null; 15 | 16 | [TestInitialize] 17 | public void InitializeTests() 18 | { 19 | RunspaceConfiguration config = RunspaceConfiguration.Create(); 20 | 21 | PSSnapInException warning; 22 | 23 | config.AddPSSnapIn("ShareFile", out warning); 24 | 25 | runspace = RunspaceFactory.CreateRunspace(config); 26 | runspace.Open(); 27 | } 28 | 29 | [TestMethod] 30 | public void TM1_0_NewLoginTest() 31 | { 32 | PowerShell ps = PowerShell.Create(); 33 | 34 | ps.AddCommand("Add-PSSnapIn"); 35 | ps.AddArgument("ShareFile"); 36 | 37 | Collection psObjects = ps.Invoke(); 38 | 39 | ps.Commands.Clear(); 40 | ps.AddCommand("New-SFClient"); 41 | ps.AddParameter("Name", Utils.LoginFilePath); 42 | 43 | psObjects = ps.Invoke(); 44 | 45 | Assert.AreEqual(1, psObjects.Count); 46 | } 47 | 48 | 49 | [TestMethod] 50 | public void TM2_GetLoginTest() 51 | { 52 | using (Pipeline pipeline = runspace.CreatePipeline()) 53 | { 54 | Command command = new Command("Get-SfClient"); 55 | command.Parameters.Add(new CommandParameter("Name", Utils.LoginFilePath)); 56 | 57 | pipeline.Commands.Add(command); 58 | 59 | Collection psObjects = pipeline.Invoke(); 60 | Assert.AreEqual(1, psObjects.Count); 61 | Assert.AreEqual(psObjects[0].BaseObject.ToString(), "ShareFile.Api.Powershell.PSShareFileClient"); 62 | } 63 | } 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Samples/AutoArchiveFiles.ps1: -------------------------------------------------------------------------------- 1 | Add-PSSnapIn ShareFile 2 | 3 | ################################################################################ 4 | # AutoArchiveFiles.ps1 5 | # 6 | # This script will move all files in the specified Parent folder to 7 | # a sub folder named the current date 8 | # 9 | # 10 | 11 | #Set this to the Id of the folder all the files are uploaded to 12 | $parentID = "Enter Parent Folder ID here" 13 | #Set this to the number of files you want to process at a time (recommended 1000 or less) 14 | $filesAtOnce = 1000; 15 | 16 | #Run the following interactively to create a login token that can be used by Get-SfClient in unattended scripts 17 | #$sfClient = New-SfClient -Name ((Join-Path $env:USERPROFILE "Documents") + "\YourSubdomain.sfps") -Account YourSubdomain 18 | $sfClient = Get-SfClient -Name ((Join-Path $env:USERPROFILE "Documents") + "\YourSubdomain.sfps") 19 | 20 | 21 | #Create a new folder named with today's date 22 | $day = Get-Date 23 | $folderName = $day.Year.ToString() + "_" + $day.Month.ToString() + "_" + $day.Day.ToString() 24 | $folderInfo ='{ 25 | "Name":"'+$folderName+'", 26 | "Description":"Auto-Generated Folder" 27 | }' 28 | $folder = Send-SfRequest -Client $sfClient -Entity Items -Method POST -Id $parentID -Navigation Folder -BodyText $folderInfo 29 | 30 | 31 | #We want to know how many files we'll be moving 32 | $pFolder = Send-SfRequest -Client $sfClient -Entity Items -Id $parentID 33 | 34 | #We don't want to grab too many files at once so I limited it to 1000 at a time 35 | for($x=0; $x -le $pFolder.FileCount; $x+=$filesAtOnce){ 36 | 37 | #We only need the file ID and the type in order to move so we make a minimal query adding in the top to grab only 1000 files at a time 38 | $files += Send-SfRequest -Client $sfClient -Entity Items -Id $parentID -Navigation Children -Select Id -Parameters @{'$top' = "$filesAtOnce"; '$skip' = "$x"} 39 | } 40 | 41 | $fileParent = '{ 42 | "Parent": {"Id": "'+ $folder.Id +'"} 43 | }' 44 | 45 | #Once we have the files we move them 46 | foreach($file in $files){ 47 | if ($file.GetType().ToString() -eq "ShareFile.Api.Client.Models.File"){ 48 | Send-SfRequest -Client $sfClient -Entity Items -Method PATCH -Id $file.Id.ToString() -BodyText $fileParent 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ShareFileSnapIn/ShareFilePSSnapIn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.ComponentModel; 7 | using System.Management.Automation; 8 | using ShareFile.Api.Powershell.Properties; 9 | using System.Reflection; 10 | using System.Collections; 11 | 12 | namespace ShareFile.Api.Powershell 13 | { 14 | [RunInstaller(true)] 15 | public class ShareFilePSSnapIn : PSSnapIn 16 | { 17 | 18 | /// 19 | /// Create an instance of the GetProcPSSnapIn01 class. 20 | /// 21 | public ShareFilePSSnapIn() 22 | : base() 23 | { 24 | } 25 | 26 | /// 27 | /// Specify the name of the PowerShell snap-in. 28 | /// 29 | public override string Name 30 | { 31 | get 32 | { 33 | return "ShareFile"; 34 | } 35 | } 36 | 37 | /// 38 | /// Specify the vendor for the PowerShell snap-in. 39 | /// 40 | public override string Vendor 41 | { 42 | get 43 | { 44 | return "Citrix"; 45 | } 46 | } 47 | 48 | /// 49 | /// Specify a description of the PowerShell snap-in. 50 | /// 51 | public override string Description 52 | { 53 | get 54 | { 55 | return "PowerShell Snap-In for ShareFile API. Version " + Resources.Version; 56 | } 57 | } 58 | 59 | /// The format file for the snap-in. 60 | private string[] _formats = { "ShareFile.Format.ps1xml" }; 61 | public override string[] Formats { get { return _formats ; } } 62 | 63 | public static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args) 64 | { 65 | if (args.Name.StartsWith("System.Net.Http.Primitives")) 66 | { 67 | var assembly = System.Reflection.Assembly.LoadFrom("System.Net.Http.Primitives.dll"); 68 | return assembly; 69 | } 70 | return null; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Parallel/Utility.cs: -------------------------------------------------------------------------------- 1 | using ShareFile.Api.Client.Models; 2 | using System; 3 | using System.IO; 4 | using System.Management.Automation; 5 | using System.Security.Cryptography; 6 | using System.Text; 7 | 8 | namespace ShareFile.Api.Powershell.Parallel 9 | { 10 | class Utility 11 | { 12 | #region Local Variables 13 | public const string DefaultSharefileFolder = "My Files & Folders"; 14 | #endregion 15 | 16 | public static String GetMD5HashFromFile(Stream file) 17 | { 18 | MD5 md5 = new MD5CryptoServiceProvider(); 19 | byte[] retVal = md5.ComputeHash(file); 20 | file.Close(); 21 | StringBuilder sb = new StringBuilder(); 22 | 23 | for (int i = 0; i < retVal.Length; i++) 24 | { 25 | sb.Append(retVal[i].ToString("x2")); 26 | } 27 | return sb.ToString(); 28 | } 29 | 30 | public static String GetMD5HashFromFile(String fileName) 31 | { 32 | string fileHashCode = string.Empty; 33 | using (FileStream file = new FileStream(fileName, FileMode.Open)) 34 | { 35 | 36 | fileHashCode = GetMD5HashFromFile(file); 37 | file.Close(); 38 | } 39 | 40 | return fileHashCode; 41 | } 42 | 43 | /// 44 | /// Resolve ShareFile item path if ShareFile drive letter or root folder is not provided 45 | /// 46 | public static Item ResolveShareFilePath(PSDriveInfo driveInfo, string path) 47 | { 48 | var item = ShareFileProvider.GetShareFileItem((ShareFileDriveInfo)driveInfo, path, null, null); 49 | 50 | // if user didn't specify the Sharefile HomeFolder in path then append in path 51 | // e.g. if user tries sf:/Folder1 as sharefile source then resolve this path to sf:/My Files & Folders/Folder1 52 | if (item == null && !path.StartsWith(String.Format(@"\{0}\", DefaultSharefileFolder))) 53 | { 54 | string updatedPath = String.Format(@"\{0}\{1}", DefaultSharefileFolder, path); 55 | item = ShareFileProvider.GetShareFileItem((ShareFileDriveInfo)driveInfo, updatedPath, null, null); 56 | } 57 | 58 | return item; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Resume/SupportHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Xml.Serialization; 5 | 6 | namespace ShareFile.Api.Powershell.Resume 7 | { 8 | /// 9 | /// Object Serializer/De-Serializer class to save and load file 10 | /// 11 | /// Generic type 12 | class SupportHandler where T : class 13 | { 14 | private static readonly object syncFileLock = new object(); 15 | 16 | /// 17 | /// Load/de-serialize file to object 18 | /// 19 | /// Path + File Name 20 | /// File Object 21 | public static T Load(string path) 22 | { 23 | lock (syncFileLock) 24 | { 25 | T serializableObject = null; 26 | 27 | using (Stream textReader = CreateTextReader(path)) 28 | { 29 | XmlSerializer xmlSerializer = CreateXmlSerializer(); 30 | serializableObject = xmlSerializer.Deserialize(textReader) as T; 31 | 32 | textReader.Close(); 33 | } 34 | 35 | return serializableObject; 36 | } 37 | } 38 | 39 | /// 40 | /// Save/serialize object to file 41 | /// 42 | /// Serializable class object 43 | /// Path + File Name 44 | public static void Save(T serializableObject, string path) 45 | { 46 | lock (syncFileLock) 47 | { 48 | using (Stream textWriter = CreateTextWriter(path)) 49 | { 50 | XmlSerializer xmlSerializer = CreateXmlSerializer(); 51 | xmlSerializer.Serialize(textWriter, serializableObject); 52 | 53 | textWriter.Close(); 54 | } 55 | } 56 | } 57 | 58 | #region Private 59 | 60 | private static Stream CreateTextReader(string path) 61 | { 62 | Stream textReader = new FileStream(path, FileMode.Open); 63 | 64 | return textReader; 65 | } 66 | 67 | private static Stream CreateTextWriter(string path) 68 | { 69 | Stream textWriter = new FileStream(path, FileMode.Create); 70 | 71 | return textWriter; 72 | } 73 | 74 | private static XmlSerializer CreateXmlSerializer() 75 | { 76 | Type ObjectType = typeof(T); 77 | 78 | XmlSerializer xmlSerializer = new XmlSerializer(ObjectType); 79 | 80 | return xmlSerializer; 81 | } 82 | 83 | #endregion 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Browser/OAuthAuthenticationForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ShareFile.Api.Powershell.Browser 2 | { 3 | partial class OAuthAuthenticationForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.webViewBrowser = new Microsoft.Web.WebView2.WinForms.WebView2(); 32 | ((System.ComponentModel.ISupportInitialize)(this.webViewBrowser)).BeginInit(); 33 | this.SuspendLayout(); 34 | // 35 | // webViewBrowser 36 | // 37 | this.webViewBrowser.AllowExternalDrop = true; 38 | this.webViewBrowser.CreationProperties = null; 39 | this.webViewBrowser.DefaultBackgroundColor = System.Drawing.Color.White; 40 | this.webViewBrowser.Dock = System.Windows.Forms.DockStyle.Fill; 41 | this.webViewBrowser.Location = new System.Drawing.Point(0, 0); 42 | this.webViewBrowser.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); 43 | this.webViewBrowser.Name = "webViewBrowser"; 44 | this.webViewBrowser.Size = new System.Drawing.Size(879, 825); 45 | this.webViewBrowser.TabIndex = 0; 46 | this.webViewBrowser.ZoomFactor = 1D; 47 | // 48 | // OAuthAuthenticationForm 49 | // 50 | this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); 51 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 52 | this.ClientSize = new System.Drawing.Size(879, 825); 53 | this.Controls.Add(this.webViewBrowser); 54 | this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); 55 | this.Name = "OAuthAuthenticationForm"; 56 | this.Text = "Authentication"; 57 | ((System.ComponentModel.ISupportInitialize)(this.webViewBrowser)).EndInit(); 58 | this.ResumeLayout(false); 59 | 60 | } 61 | 62 | #endregion 63 | 64 | private Microsoft.Web.WebView2.WinForms.WebView2 webViewBrowser; 65 | } 66 | } -------------------------------------------------------------------------------- /ShareFileSnapIn-Installer-x32/ShareFileSnapIn-Installer-x32.wixproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | x86 6 | 3.7 7 | 95c5e31f-38ae-463d-b4a9-deb5c28442a2 8 | 2.0 9 | ShareFileSnapIn-Installer-x32 10 | Package 11 | $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets 12 | $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets 13 | 14 | 15 | bin\$(Configuration)\ 16 | obj\$(Configuration)\ 17 | Debug 18 | 19 | 20 | bin\$(Configuration)\ 21 | obj\$(Configuration)\ 22 | 23 | 24 | 25 | 26 | 27 | 28 | ShareFileSnapIn 29 | {db7fd2e6-2884-4e66-bfd8-219c007da4cb} 30 | True 31 | True 32 | Binaries;Content;Satellites 33 | INSTALLFOLDER 34 | 35 | 36 | 37 | 38 | $(WixExtDir)\WixNetFxExtension.dll 39 | WixNetFxExtension 40 | 41 | 42 | $(WixExtDir)\WixUtilExtension.dll 43 | WixUtilExtension 44 | 45 | 46 | $(WixExtDir)\WixUIExtension.dll 47 | WixUIExtension 48 | 49 | 50 | $(WixExtDir)\WixPSExtension.dll 51 | WixPSExtension 52 | 53 | 54 | 55 | 56 | 57 | 58 | 66 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Parallel/DownloadAction.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace ShareFile.Api.Powershell.Parallel 4 | { 5 | /// 6 | /// DownloadAction class to download files from ShareFile server 7 | /// 8 | class DownloadAction : IAction 9 | { 10 | private Client.Models.File child; 11 | private Client.ShareFileClient client; 12 | private int downloadId; 13 | private FileSystemInfo target; 14 | private ActionType actionType; 15 | private FileSupport fileSupportDelegate; 16 | private string fileName; 17 | public string FileName 18 | { 19 | get 20 | { 21 | return fileName; 22 | } 23 | } 24 | public ActionType OpActionType 25 | { 26 | get 27 | { 28 | return actionType; 29 | } 30 | set 31 | { 32 | actionType = value; 33 | } 34 | } 35 | 36 | public DownloadAction(FileSupport fileSupport, Client.ShareFileClient client, int downloadId, Client.Models.File child, FileSystemInfo target, ActionType type) 37 | { 38 | this.child = child; 39 | this.client = client; 40 | this.downloadId = downloadId; 41 | this.target = target; 42 | this.actionType = type; 43 | this.fileSupportDelegate = fileSupport; 44 | } 45 | 46 | void IAction.CopyFileItem(ProgressInfo progressInfo) 47 | { 48 | fileName = System.IO.Path.Combine(target.FullName, child.FileName); 49 | bool duplicateFile = File.Exists(fileName); 50 | bool hashcodeMatches = duplicateFile ? Utility.GetMD5HashFromFile(fileName).Equals(child.Hash) : false; 51 | 52 | if (duplicateFile && actionType == ActionType.None) 53 | { 54 | throw new IOException("File already exist"); 55 | } 56 | else if (!duplicateFile || actionType == ActionType.Force || (actionType == ActionType.Sync && !hashcodeMatches)) 57 | { 58 | using (var fileStream = new FileStream(fileName, actionType == ActionType.Force || actionType == ActionType.Sync ? FileMode.Create : FileMode.CreateNew)) 59 | { 60 | var downloader = client.GetAsyncFileDownloader(child); 61 | 62 | progressInfo.ProgressTotal(progressInfo.FileIndex, child.FileSizeBytes.GetValueOrDefault()); 63 | 64 | downloader.OnTransferProgress += 65 | (sender, args) => 66 | { 67 | if (args.Progress.TotalBytes > 0) 68 | { 69 | progressInfo.ProgressTransferred(progressInfo.FileIndex, args.Progress.BytesTransferred); 70 | } 71 | }; 72 | 73 | downloader.DownloadToAsync(fileStream).Wait(); 74 | 75 | fileStream.Close(); 76 | fileSupportDelegate(fileName); 77 | } 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /ShareFileSnapIn-Installer-x64/ShareFileSnapIn-Installer-x64.wixproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | x86 6 | 3.7 7 | de4a9e57-e80e-44d8-8e3a-de21c39a3d3d 8 | 2.0 9 | ShareFileSnapIn-Installer-x64 10 | Package 11 | $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets 12 | $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets 13 | 14 | 15 | bin\$(Configuration)\ 16 | obj\$(Configuration)\ 17 | Debug 18 | 19 | 20 | bin\$(Configuration)\ 21 | obj\$(Configuration)\ 22 | 23 | 24 | 25 | 26 | 27 | 28 | ShareFileSnapIn 29 | {db7fd2e6-2884-4e66-bfd8-219c007da4cb} 30 | True 31 | True 32 | Binaries;Content;Satellites 33 | INSTALLFOLDER 34 | 35 | 36 | 37 | 38 | $(WixExtDir)\WixBalExtension.dll 39 | WixBalExtension 40 | 41 | 42 | $(WixExtDir)\WixNetFxExtension.dll 43 | WixNetFxExtension 44 | 45 | 46 | $(WixExtDir)\WixUtilExtension.dll 47 | WixUtilExtension 48 | 49 | 50 | $(WixExtDir)\WixUIExtension.dll 51 | WixUIExtension 52 | 53 | 54 | $(WixExtDir)\WixPSExtension.dll 55 | WixPSExtension 56 | 57 | 58 | 59 | 60 | 61 | 62 | 70 | -------------------------------------------------------------------------------- /Samples/DeleteMostRecent.ps1: -------------------------------------------------------------------------------- 1 | ################################################ 2 | # DeleteMostRecent.ps1 3 | # 4 | # This script will delete the most recent version of a file in a ShareFile user's account. 5 | # Initial use case is to overcome Cryptolock Malware. 6 | # ADDITIONAL DETAILS: http://itsme2e.com/2015/11/30/recover-from-cryptolocker-like-malware-with-sharefile/ 7 | # 8 | # This script was originally written by Thuy Nguyen (Twitter: @itsme2e) 9 | # This sample code is provided as-is and can be used freely by others 10 | # Last Revised: March 26, 2016 11 | 12 | Add-PSSnapin ShareFile 13 | 14 | # Load credentials from disk. If not there, challenge for credentials and store for future use 15 | # Modify the path to match your desired location 16 | If (test-path "$env:USERPROFILE\Documents\myauth.sfps”) 17 | { 18 | $client=Get-sfclient –Name "$env:USERPROFILE\Documents\myauth.sfps” 19 | } 20 | Else 21 | { 22 | 23 | New-sfclient –Name "$env:USERPROFILE\Documents\myauth.sfps” 24 | $client=get-sfclient –Name "$env:USERPROFILE\Documents\myauth.sfps” 25 | } 26 | 27 | 28 | Function GetUser{ 29 | $EmailAddress = Read-host "Email Address of User" 30 | # $DateOfAttack = Read-Host "Date of infection" 31 | 32 | $DateofAttack = GetDate; 33 | 34 | # Pulls the user object based on email address 35 | $sfUser = Send-SfRequest -Client $client -Entity Users -Parameters @{"emailaddress" = $EmailAddress} 36 | 37 | # Transform 38 | $HomeFolderID = "Users(" + $sfuser.Id + ")/HomeFolder" 39 | 40 | # Pull Children 41 | $sfHomeFolder = Send-SfRequest -client $client -entity $HomeFolderID -expand "Children" 42 | 43 | CheckVersions $sfHomeFolder $DateOfAttack 44 | 45 | } 46 | 47 | Function GetDate{ 48 | $date = Read-Host "Date of infection/cryptolock" 49 | if (($date -as [DateTime]) -ne $null) { 50 | $date = [DateTime]::Parse($date) 51 | Write-Host $date 52 | Return $date; 53 | 54 | } else { 55 | Write-Host "Invalid date format" 56 | GetDate; 57 | } 58 | 59 | } 60 | 61 | Function CheckVersions($FolderRoot, $Dateofincident){ 62 | 63 | # loop through children objects 64 | foreach($item in $FolderRoot.children){ 65 | 66 | $time = New-TimeSpan -Start $Dateofincident -End $item.creationdate 67 | 68 | # Write-Host "date of upload " $item.creationdate 69 | # Check if Item is a file 70 | if ($item.__type -eq "ShareFile.Api.Client.Models.File"){ 71 | 72 | # If there are multiple versions and the date of upload was within the 1 day span of infection 73 | if (($item.HasMultipleVersions -eq "true") -and ($time.days -le 1)) { 74 | 75 | # Delete File 76 | Send-SfRequest -client $client -entity Items -Method Delete -Id $item.id -Parameters @{"singleversion" = "true"} 77 | } 78 | 79 | else { 80 | # Write-Host $item.name " is the only version" 81 | } 82 | } 83 | 84 | # Item is a Folder; send back to CheckVersions 85 | if ($item.__type -eq "ShareFile.Api.Client.Models.Folder"){ 86 | $newRoot = Send-SfRequest -client $client -Entity Items -Id $item.id -expand "Children" 87 | CheckVersions $newRoot $Dateofincident 88 | } 89 | 90 | } 91 | } 92 | 93 | GetUser; 94 | -------------------------------------------------------------------------------- /Test-ShareFileSnapIn/MapDriveTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.ObjectModel; 4 | using System.Management.Automation; 5 | using System.Management.Automation.Runspaces; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | using ShareFile.Api.Powershell; 8 | 9 | namespace Test_ShareFileSnapIn 10 | { 11 | [TestClass] 12 | public class MapDriveTests 13 | { 14 | private Runspace runspace = null; 15 | private PSObject sfLogin = null; 16 | 17 | [TestInitialize] 18 | public void InitializeTests() 19 | { 20 | 21 | RunspaceConfiguration config = RunspaceConfiguration.Create(); 22 | 23 | PSSnapInException warning; 24 | 25 | config.AddPSSnapIn("ShareFile", out warning); 26 | 27 | runspace = RunspaceFactory.CreateRunspace(config); 28 | runspace.Open(); 29 | 30 | // do login first to start tests 31 | using (Pipeline pipeline = runspace.CreatePipeline()) 32 | { 33 | 34 | Command command = new Command("Get-SfClient"); 35 | command.Parameters.Add(new CommandParameter("Name", Utils.LoginFilePath)); 36 | 37 | pipeline.Commands.Add(command); 38 | 39 | Collection objs = pipeline.Invoke(); 40 | Assert.AreEqual(1, objs.Count); 41 | sfLogin = objs[0]; 42 | } 43 | } 44 | 45 | [TestMethod] 46 | public void TM1_MapDriveTest() 47 | { 48 | using (Pipeline pipeline = runspace.CreatePipeline()) 49 | { 50 | Command command = new Command("New-PSDrive"); 51 | command.Parameters.Add("Name", Utils.ShareFileDriveLetter); 52 | command.Parameters.Add("PSProvider", "ShareFile"); 53 | command.Parameters.Add("Root", "/"); 54 | command.Parameters.Add("Client", sfLogin); 55 | 56 | pipeline.Commands.Add(command); 57 | 58 | Collection psObjects = pipeline.Invoke(); 59 | 60 | // Drive is successfully mapped to root folder 61 | Assert.AreEqual(1, psObjects.Count); 62 | PSObject sfDrive = psObjects[0]; 63 | Assert.IsNotNull(sfDrive); 64 | } 65 | } 66 | 67 | [TestMethod] 68 | public void TM2_CheckHomeContentsTest() 69 | { 70 | Pipeline pipeline = runspace.CreatePipeline(); 71 | 72 | Command command = new Command("New-PSDrive"); 73 | command.Parameters.Add("Name", Utils.ShareFileDriveLetter); 74 | command.Parameters.Add("PSProvider", "ShareFile"); 75 | command.Parameters.Add("Root", "/My Files & Folders"); 76 | command.Parameters.Add("Client", sfLogin); 77 | 78 | pipeline.Commands.Add(command); 79 | Collection psObjects = pipeline.Invoke(); 80 | Assert.AreEqual(1, psObjects.Count); 81 | 82 | pipeline = runspace.CreatePipeline(); 83 | command = new Command("Get-ChildItem"); 84 | 85 | pipeline.Commands.Add(command); 86 | 87 | pipeline.Input.Write(Utils.ShareFileDrivePath); 88 | psObjects = pipeline.Invoke(); 89 | Assert.AreNotEqual(0, psObjects.Count); 90 | } 91 | 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Samples/DownloadFileBasedOnShareID.ps1: -------------------------------------------------------------------------------- 1 | # PowerShell script that will download a file to the local filesystem based on the Share URL 2 | # This script currently only works with Share URLs that are send to users already on the ShareFile system. Share URLs that include the activation ID (&a=xxxx) will not work without removal of that part 3 | # PLEASE NOTE: This script has a dependency on another script posted to https://github.com/citrix/ShareFile-PowerShell 4 | # 5 | # This script was originally written by Joel Stocker (Twitter: @sharefilejoel) 6 | # This sample code is provided as-is and can be used freely by others 7 | # Last Revised: March 26, 2016 8 | 9 | Param ( [string]$sharelinkurl ) 10 | #Param ( [string]$linkshareid ) #Instead of using the Share URL, you could also use the the ShareID. If so, please remove or comment out the line above and comment out the section below the authentication part 11 | $DownloadScript = "C:\Scripts\DownloadScript.ps1" #This PS script calls another script, please ensure the correct path to the Download Script 12 | 13 | # Load ShareFile PowerSHell Snap-in. The Snap-in can be found on GitHub https://github.com/citrix/ShareFile-PowerShell 14 | Add-PSSnapIn ShareFile 15 | 16 | # Load credentials from disk. If not there, challenge for credentials and store for future use 17 | # Modify the path to match your desired location 18 | If (test-path "$env:USERPROFILE\Documents\myauth.sfps") 19 | { 20 | $sfclient=Get-sfclient "$env:USERPROFILE\Documents\myauth.sfps" 21 | } 22 | Else 23 | { 24 | 25 | New-sfclient "$env:USERPROFILE\Documents\myauth.sfps" 26 | $sfclient=get-sfclient "$env:USERPROFILE\Documents\myauth.sfps" 27 | } 28 | 29 | # This code is only relevant if using the full Share URL, see comments above 30 | # It determines if the Share URL is formatted as /d/ or /d- and based on that extracts the last 16 or 17 chars respectively 31 | # Please comment out this section when using Share ID 32 | if ($sharelinkurl -match '\/d\/') 33 | 34 | {$linkshareid = $sharelinkurl.substring($sharelinkurl.length - 16, 16)} 35 | 36 | Else { 37 | 38 | if ($sharelinkurl -match '\/d\-') 39 | {$linkshareid = $sharelinkurl.substring($sharelinkurl.length - 17, 17)} 40 | 41 | Else {"Not a Share URL or incorrect formatting" 42 | break} 43 | 44 | } 45 | # End of code for using the Share URL 46 | 47 | # Get a list of Item IDs contained in the Share 48 | $shareid = Send-SfRequest -Client $sfclient -Entity Shares -Id $linkshareid 49 | $shareitems = Send-SfRequest -Client $sfclient -Entity Shares -Id $shareid.Id -Expand Items 50 | $itemids = $shareitems.Items.Id 51 | 52 | # Create an empty array to store the filesystem destination location 53 | $filelocations = @() #(not being used in this scipt) 54 | 55 | $numberofitems = $shareitems.items.count #count the number of items in the download (not being used in this script) 56 | 57 | # Set the root folder to download to 58 | $rootfolder = "C:\Archive\" #Modify this based on what local root folder you want to download the files to. This folder needs to exist 59 | # Set the subfolder value to be the ShareID 60 | $subfolder = $linkshareid 61 | # Set the rootfolder and subfolder path 62 | $destDir = $rootfolder + $subfolder 63 | 64 | "Download Folder Location: " + $destdir #Return the download path 65 | 66 | # Start the Download Script 67 | start-job -Name "Download" -FilePath $DownloadScript -ArgumentList $itemids,$destDir | wait-job 68 | Receive-job -Name "Download" 69 | #start-job -Name "Copy" -FilePath $DownloadScript -ArgumentList $itemids,$destDir | Out-Null # Use if you don't want to see job status on screen. Comment out the 2 lines above 70 | 71 | -------------------------------------------------------------------------------- /ShareFileSnapIn/WebpopInternetExplorerMode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.Win32; 4 | 5 | namespace ShareFile.Api.Powershell 6 | { 7 | public class WebpopInternetExplorerMode 8 | { 9 | private const string InternetExplorerEmulationRegistryKey = @"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION"; 10 | private const string InternetExplorerInstalledVersionKey = @"Software\Microsoft\Internet Explorer"; 11 | private const string InternetExplorerVersionKeyName = "svcVersion"; 12 | private const string InternetExplorerVersionKeyNameOld = "Version"; 13 | 14 | public static bool SetUseCurrentIERegistryKey() 15 | { 16 | var ieVersion = GetInstalledInternetExplorerVersion() ?? InternetExplorerVersion.IE9; 17 | return SetInternetExplorerEmulationRegistryKey(ieVersion); 18 | } 19 | 20 | public static InternetExplorerVersion? GetInstalledInternetExplorerVersion() 21 | { 22 | Func getInstalledVersion = keyName => ParseInternetExplorerVersionString(GetRegistryString(Registry.LocalMachine, InternetExplorerInstalledVersionKey, keyName)); 23 | return getInstalledVersion(InternetExplorerVersionKeyName) ?? getInstalledVersion(InternetExplorerVersionKeyNameOld); 24 | } 25 | 26 | private static InternetExplorerVersion? ParseInternetExplorerVersionString(string version) 27 | { 28 | if (String.IsNullOrEmpty(version)) 29 | { 30 | return null; 31 | } 32 | 33 | int dotIndex = version.IndexOf('.'); 34 | if (dotIndex == -1) 35 | { 36 | return null; 37 | } 38 | 39 | string majorVersionString = version.Substring(0, dotIndex); 40 | int majorVersion; 41 | if (!int.TryParse(majorVersionString, out majorVersion)) 42 | { 43 | return null; 44 | } 45 | 46 | majorVersion *= 1000; 47 | 48 | if (Enum.GetValues(typeof(InternetExplorerVersion)).Cast().Contains(majorVersion)) 49 | { 50 | return (InternetExplorerVersion)majorVersion; 51 | } 52 | else 53 | { 54 | return null; 55 | } 56 | } 57 | 58 | private static string GetRegistryString(RegistryKey parent, string keyPath, string keyName) 59 | { 60 | try 61 | { 62 | using (var regKey = parent.OpenSubKey(keyPath)) 63 | { 64 | return regKey.GetValue(keyName) as string; 65 | } 66 | } 67 | catch 68 | { 69 | return null; 70 | } 71 | } 72 | 73 | public static bool SetInternetExplorerEmulationRegistryKey(InternetExplorerVersion ieVersion) 74 | { 75 | return SetInternetExplorerEmulationRegistryKey((ieVersion == InternetExplorerVersion.None) ? null : (int?)ieVersion); 76 | } 77 | 78 | public static bool SetInternetExplorerEmulationRegistryKey(int? ieVersion) 79 | { 80 | try 81 | { 82 | using (var regKey = Registry.CurrentUser.CreateSubKey(InternetExplorerEmulationRegistryKey, RegistryKeyPermissionCheck.ReadWriteSubTree)) //opens an existing subkey or creates it 83 | { 84 | string appName = "powershell.exe"; 85 | if (ieVersion.HasValue) 86 | { 87 | regKey.SetValue(appName, ieVersion.Value, RegistryValueKind.DWord); 88 | } 89 | else 90 | { 91 | regKey.DeleteValue(appName); 92 | } 93 | } 94 | 95 | return true; 96 | } 97 | catch 98 | { 99 | return false; 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Parallel/UploadAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using ShareFile.Api.Client.Exceptions; 5 | using ShareFile.Api.Client.Models; 6 | using ShareFile.Api.Client.Transfers; 7 | 8 | namespace ShareFile.Api.Powershell.Parallel 9 | { 10 | /// 11 | /// UploadAction class to upload file to ShareFile server 12 | /// 13 | class UploadAction : IAction 14 | { 15 | private FileSystemInfo child; 16 | private Client.ShareFileClient client; 17 | private Item uploadTarget; 18 | private String details; 19 | private FileSupport fileSupportDelegate; 20 | private ActionType actionType; 21 | private string fileName; 22 | public string FileName 23 | { 24 | get 25 | { 26 | return fileName; 27 | } 28 | } 29 | public ActionType OpActionType 30 | { 31 | get 32 | { 33 | return actionType; 34 | } 35 | set 36 | { 37 | actionType = value; 38 | } 39 | } 40 | 41 | public UploadAction(FileSupport fileSupport, Client.ShareFileClient client, FileSystemInfo source, Item target, String details, ActionType type) 42 | { 43 | this.client = client; 44 | this.child = source; 45 | this.uploadTarget = target; 46 | this.details = details; 47 | this.fileSupportDelegate = fileSupport; 48 | actionType = type; 49 | } 50 | 51 | void IAction.CopyFileItem(ProgressInfo progressInfo) 52 | { 53 | var fileInfo = (FileInfo)child; 54 | Item fileItem = null; 55 | fileName = child.Name; 56 | try 57 | { 58 | fileItem = client.Items.ByPath(uploadTarget.url, "/" + child.Name).Execute(); 59 | } 60 | catch (ODataException e) { 61 | if (e.Code != System.Net.HttpStatusCode.NotFound) 62 | { 63 | throw e; 64 | } 65 | } 66 | 67 | bool duplicate = fileItem != null && fileItem is Client.Models.File; 68 | bool hashcodeMatches = duplicate ? (fileItem as Client.Models.File).Hash.Equals(Utility.GetMD5HashFromFile(child.FullName)) : false; 69 | 70 | if (duplicate && actionType == ActionType.None) 71 | { 72 | throw new IOException("File already exist"); 73 | } 74 | else if (!duplicate || actionType == ActionType.Force || (actionType == ActionType.Sync && !hashcodeMatches )) 75 | { 76 | var uploadSpec = new UploadSpecificationRequest 77 | { 78 | CanResume = false, 79 | Details = details, 80 | FileName = fileInfo.Name, 81 | FileSize = fileInfo.Length, 82 | Method = UploadMethod.Threaded, 83 | Parent = uploadTarget.url, 84 | ThreadCount = 4, 85 | Raw = true 86 | }; 87 | 88 | using (var fileStream = fileInfo.OpenRead()) 89 | { 90 | var uploader = client.GetAsyncFileUploader(uploadSpec, fileStream); 91 | 92 | progressInfo.ProgressTotal(progressInfo.FileIndex, fileInfo.Length); 93 | 94 | uploader.OnTransferProgress += 95 | (sender, args) => 96 | { 97 | if (args.Progress.TotalBytes > 0) 98 | { 99 | progressInfo.ProgressTransferred(progressInfo.FileIndex, args.Progress.BytesTransferred); 100 | } 101 | 102 | }; 103 | 104 | Task.Run(() => uploader.UploadAsync()).Wait(); 105 | fileSupportDelegate(fileInfo.Name); 106 | } 107 | } 108 | } 109 | 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Samples/DownloadScript.ps1: -------------------------------------------------------------------------------- 1 | # PowerShell script that will download file(s) based on one or more ItemID (called by different script) 2 | # PLEASE NOTE: This script has a dependency on another script posted to https://github.com/citrix/ShareFile-PowerShell 3 | # 4 | # This script was originally written by Joel Stocker (Twitter: @sharefilejoel) 5 | # This sample code is provided as-is and can be used freely by others 6 | # Last Revised: March 26, 2016 7 | 8 | Param ( [string[]]$itemids, [string]$destDir ) 9 | 10 | # Load ShareFile PowerSHell Snap-in. The Snap-in can be found on GitHub https://github.com/citrix/ShareFile-PowerShell 11 | Add-PSSnapIn ShareFile 12 | 13 | # Load credentials from disk. If not there, challenge for credentials and store for future use 14 | # Modify the path to match your desired location 15 | If (test-path "$env:USERPROFILE\Documents\myauth.sfps") 16 | { 17 | $sfclient=Get-sfclient "$env:USERPROFILE\Documents\myauth.sfps" 18 | } 19 | Else 20 | { 21 | 22 | New-sfclient "$env:USERPROFILE\Documents\myauth.sfps" 23 | $sfclient=get-sfclient "$env:USERPROFILE\Documents\myauth.sfps" 24 | } 25 | 26 | # Create empty array 27 | $filelocations = @() 28 | 29 | # Go through list of ItemIDs 30 | foreach ($itemid in $itemids) { 31 | 32 | 33 | # Get Download URL from API 34 | $downloadlink = Send-SfRequest -Client $sfclient -Method GET -Uri "https://techteam.sf-api.com/sf/v3/Items($itemid)/Download?includeallversions=false&redirect=false" -Expand DownloadUrl 35 | $downloadurl = $downloadlink.DownloadUrl.AbsoluteUri 36 | 37 | 38 | # Check if the destinaton folder exist 39 | # If it does exist, just download there 40 | If (Test-Path $destDir) { 41 | 42 | # Get Timestamp in epoch seconds. This will be used as part of the filename to avoid overwriting files 43 | $timestamp = Get-Date -UFormat "%s" 44 | # Get filename for file being downloaded 45 | $sfItem = Send-SfRequest -Client $sfClient -Method GET -Entity Items -Id $itemid 46 | $filename = $sfItem.FileName 47 | 48 | $localdest = $destDir + "\" + $timestamp + "_" + $filename 49 | 50 | # Download & Save 51 | $start_time = Get-Date 52 | Import-Module BitsTransfer 53 | $job = Start-BitsTransfer -Asynchronous -Source $downloadurl -Destination $localdest 54 | 55 | while (($Job.JobState -eq "Transferring") -or ($Job.JobState -eq "Connecting")) ` 56 | { sleep 5;} # Poll for status, sleep for 5 seconds, or perform an action. 57 | 58 | Switch($Job.JobState) 59 | { 60 | "Transferred" {Complete-BitsTransfer -BitsJob $Job} 61 | "Error" {$Job | Format-List } # List the errors. 62 | default {"Other action"} # Perform corrective action. 63 | } 64 | 65 | $filelocations += "Original Filename: " + $filename + " - Download Location: " + $localdest 66 | 67 | # "Time taken: $((Get-Date).Subtract($start_time).Seconds) second(s)" # Not being used in script 68 | 69 | } 70 | 71 | # If the subfolder doesn't exist, create it and start download 72 | Else { 73 | 74 | New-Item -Path $destDir -ItemType Directory | Out-Null 75 | 76 | # Get Timestamp in epoch seconds. This will be used as part of the filename to avoid overwriting files 77 | $timestamp = Get-Date -UFormat "%s" 78 | # Get filename for file being downloaded 79 | $sfItem = Send-SfRequest -Client $sfClient -Method GET -Entity Items -Id $itemid 80 | $filename = $sfItem.FileName 81 | 82 | $localdest = $destDir + "\" + $timestamp + "_" + $filename 83 | 84 | # Download & Save 85 | $start_time = Get-Date 86 | Import-Module BitsTransfer 87 | $job = Start-BitsTransfer -Asynchronous -Source $downloadurl -Destination $localdest 88 | 89 | while (($Job.JobState -eq "Transferring") -or ($Job.JobState -eq "Connecting")) ` 90 | { sleep 5;} # Poll for status, sleep for 5 seconds, or perform an action. 91 | 92 | Switch($Job.JobState) 93 | { 94 | "Transferred" {Complete-BitsTransfer -BitsJob $Job} 95 | "Error" {$Job | Format-List } # List the errors. 96 | default {"Other action"} # Perform corrective action. 97 | } 98 | 99 | $filelocations += "Original Filename: " + $filename + " - Download Location: " + $localdest 100 | 101 | # "Time taken: $((Get-Date).Subtract($start_time).Seconds) second(s)" # Not being used in script 102 | } 103 | } 104 | 105 | "`n" 106 | "Files Downloaded:" 107 | $filelocations 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ShareFile PowerShell SDK 2 | ======================== 3 | The ShareFile PowerShell SDK is a PowerShell snap-in that provides support for saving a user login for use in scripts, provides access to the ShareFile API, and also a provider that can be used within PowerShell to map to a ShareFile account. 4 | 5 | > NOTE: If looking for a PowerShell module, it can be found at https://github.com/sharefile-org/ShareFile-PowerShell-Module. 6 | > 7 | > This is the same ShareFile PowerShell SDK functionality, but supporting PowerShell 5.x and 7+ 8 | 9 | 10 | 11 | 14 | 18 | 19 | 20 | 23 | 27 | 28 | 29 | 32 | 36 | 37 | 38 | 41 | 45 | 46 | 47 | 50 | 54 | 55 | 56 | 59 | 63 | 64 | 65 | 68 | 73 | 74 |
12 | 13 | 15 | Download
16 | Download the latest release here 17 |
21 | 22 | 24 | System Requirements
25 | The PowerShell SDK requires PowerShell 4.x, .NET 4.8, and the WebView2 runtime. 26 |
30 | 31 | 33 | Getting Started
34 | Click here if you are just getting started for a list of common operations. We will walk you through your first time using the SDK using some basic operations. 35 |
39 | 40 | 42 | Sample Scripts
43 | Here you will find some example scripts that are commonly used by customers. 44 |
48 | 49 | 51 | Scheduling Scripts
52 | Found a great script that you want to run automatically on a regular basis? Check here for more information on how to schedule scripts. 53 |
57 | 58 | 60 | Syncing Files
61 | Coming from the SFCLI tool? This section contains details on how you can use the PowerShell SDK to do the same type of activities. 62 |
66 | 67 | 69 | License
70 | All code is licensed under the MIT 71 | License 72 |
75 | 76 | 77 | To follow us on the ShareFile blog, check here: 78 | https://www.sharefile.com/blogs 79 | -------------------------------------------------------------------------------- /Samples/StorageReport.ps1: -------------------------------------------------------------------------------- 1 | Add-PSSnapin ShareFile 2 | 3 | ################################################################################ 4 | # StorageReport.ps1 5 | # 6 | # This script will list all files that are in any shared folder or a user home 7 | # folder in a custom .csv file. 8 | # 9 | # Notes: 10 | # - Script should be run as a super user or user who has access to all shared 11 | # folders and all home folders 12 | 13 | #Run the following interactively to create a login token that can be used by Get-SfClient in unattended scripts 14 | #$sfClient = New-SfClient -Name ((Join-Path $env:USERPROFILE "Documents") + "\YourSubdomain.sfps") -Account YourSubdomain 15 | $sfClient = Get-SfClient -Name ((Join-Path $env:USERPROFILE "Documents") + "\YourSubdomain.sfps") 16 | 17 | #create script variable to store items and IDs that for cache lookup purposes 18 | #this is only needed for the full path details 19 | $script:StorageItemArray = @() 20 | $script:ItemIdArray = @{} 21 | $script:ItemIdArray.Add("", $null) 22 | $script:ItemIdArray.Add("root", $null) 23 | 24 | #Get shared folder root 25 | #note that this does not include size of versions that are stored but does list that there are versions 26 | function GetFileSize($ItemID, $ItemType) 27 | { 28 | #get the children of the passed in folder 29 | $Items = Send-SfRequest $sfClient -Method GET -Entity Items -Id $ItemID -Expand "Children,Owner" 30 | foreach ($item in $Items.Children) 31 | { 32 | #since folders return a 'file size' of all the children ignore unless it is a file 33 | if ($item.__type -eq "ShareFile.Api.Client.Models.File") 34 | { 35 | #CREATE A HASTHATBLE WITH ID/NAME 36 | #LOOKUP WITH PATH AND ADD FROM GET IF NOT THERE SO WE ONLY GET ONCE 37 | $FormattedPath = "" 38 | 39 | #pull apart the path and replace IDs with names 40 | foreach ($el in $Item.Path.Split("/")) 41 | { 42 | #check if we have this in cache 43 | if ($script:ItemIdArray.ContainsKey($el) -eq $true) 44 | { 45 | #make sure it isn't a value we want to ignore 46 | if ($script:ItemIdArray[$el] -ne $null) { $FormattedPath += ($script:ItemIdArray[$el] + "\") } 47 | } 48 | else 49 | { 50 | #get the name of the folder from the ID and add to cache 51 | $FolderName = Send-SfRequest $sfClient -Method GET -Entity Items -Id $el -Select "Name,Path" 52 | 53 | #if this is the root of the account we ignore it 54 | if ($FolderName.Path -eq "/root") 55 | { 56 | $script:ItemIdArray.Add($el, $null) 57 | } 58 | else 59 | { 60 | $script:ItemIdArray.Add($el, $FolderName.Name) 61 | $FormattedPath += ($FolderName.Name + "\") 62 | } 63 | } 64 | } 65 | 66 | #output an object to use in the report 67 | #could use the raw $item or could format to be 'pretty' 68 | $script:StorageItemArray += [PSCustomObject] @{Type=$ItemType; Path=$FormattedPath; Name=$item.Name; FileSizeBytes=$Item.FileSizeBytes; FileCount=$item.FileCount; DateModified=$item.CreationDate; DateAccessed=$item.ClientModifiedDate; DateCreated=$item.ClientCreatedDate; Creator=$item.CreatorNameShort; Owner=$items.Owner.Email; HasVersions=$item.HasMultipleVersions} 69 | } 70 | 71 | #determine type of item and recurse if a folder 72 | if ($item.__type -eq "ShareFile.Api.Client.Models.Folder") { GetFileSize $item.Id $ItemType} 73 | } 74 | } 75 | 76 | #Get the top-level shared folders and recurse each one 77 | $Items = Send-SfRequest $sfClient -Method GET -Entity Items -Id "allshared" -Expand "Children" 78 | foreach ($item in $Items.Children) 79 | { 80 | Write-Host ("Processing Shared Folder: {0}" -f $item.Name) 81 | GetFileSize $item.Id "Shared Folders" 82 | } 83 | 84 | 85 | $employees = Send-SfRequest $sfClient -Method GET -Entity Accounts/Employees -select "Id,Email" 86 | foreach ($employee in $employees) 87 | { 88 | Write-Host ("Processing Home Folder: {0}" -f $employee.Email) 89 | $HomeFolderID = "Users(" + $employee.Id + ")/HomeFolder" 90 | $EmployeeHomeFolder = Send-SfRequest $sfClient -Method GET -Entity $HomeFolderID -Select "Id,Name" 91 | $script:FullPath = ($EmployeeHomeFolder.Name + "\") 92 | GetFileSize $EmployeeHomeFolder.Id "Home Folder" 93 | } 94 | 95 | #output the report to CSV 96 | $script:StorageItemArray | Export-Csv -NoTypeInformation -Path ((Join-Path $env:USERPROFILE "Documents") + "\Storage." + (Get-Date -Format yyyy-MM-dd) + ".csv") 97 | -------------------------------------------------------------------------------- /Test-ShareFileSnapIn/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Test_ShareFileSnapIn 5 | { 6 | public class Utils 7 | { 8 | 9 | private static string _localFile = "ToUpload.txt"; 10 | private static string _localFolder = "Folder1"; 11 | private static string _sfFile = "DeepText.txt"; 12 | private static string _sfFolder = "Folder1Q"; 13 | 14 | /// 15 | /// C:\sflogin.sfps 16 | /// 17 | public static string LoginFilePath = @"C:\sflogin.sfps"; 18 | 19 | /// 20 | /// sf 21 | /// 22 | public static string ShareFileDriveLetter = "sf"; 23 | /// 24 | /// sf: 25 | /// 26 | public static string ShareFileDrivePath = string.Format("{0}{1}",ShareFileDriveLetter, ":"); 27 | /// 28 | /// sf:/My Files & Folders 29 | /// 30 | public static string ShareFileHomeFolder = string.Format("{0}{1}", ShareFileDrivePath, "/My Files & Folders"); 31 | 32 | /// 33 | /// sf:/Folder1 34 | /// 35 | public static string ShareFileFolder = string.Format("{0}{1}{2}", ShareFileDrivePath, "/", _localFolder); 36 | /// 37 | /// sf:/My Files & Folders/Folder1Q 38 | /// 39 | public static string ShareFileFolderUploaded = string.Format("{0}{1}{2}", ShareFileHomeFolder, "/", _sfFolder); 40 | /// 41 | /// sf:/My Files & Folders/Folder1 42 | /// 43 | public static string ShareFileFolderFullPath = string.Format("{0}{1}{2}", ShareFileHomeFolder, "/", _localFolder); 44 | /// 45 | /// sf:/DeepText.txt 46 | /// 47 | public static string ShareFileFile = string.Format("{0}{1}{2}", ShareFileDrivePath, "/", _sfFile); 48 | /// 49 | /// sf:/ToUpload.txt 50 | /// 51 | public static string ShareFileFileUploaded = string.Format("{0}{1}{2}", ShareFileHomeFolder, "/", _localFile); 52 | /// 53 | /// sf:/My Files & Folders/DeepText.txt 54 | /// 55 | public static string ShareFileFileFullPath = string.Format("{0}{1}{2}", ShareFileHomeFolder, "/", _sfFile); 56 | 57 | /// 58 | /// D:\SFTemp 59 | /// 60 | public static string LocalBaseFolder = @"D:\SFTemp"; 61 | /// 62 | /// D:\SFTemp\Folder1Q 63 | /// 64 | public static string LocalFolder = string.Format("{0}{1}{2}", LocalBaseFolder, @"\", _sfFolder); 65 | /// 66 | /// D:\SFTemp\Folder1 67 | /// 68 | public static string LocalFolderDownloaded = string.Format("{0}{1}{2}", LocalBaseFolder, @"\", _localFolder); 69 | /// 70 | /// D:\SFTemp\ToUpload.txt 71 | /// 72 | public static string LocalFile = string.Format("{0}{1}{2}", LocalBaseFolder, @"\", _localFile); 73 | /// 74 | /// D:\SFTemp\DeepText.txt 75 | /// 76 | public static string LocalFileDownloaded = string.Format("{0}{1}{2}", LocalBaseFolder, @"\", _sfFile); 77 | 78 | public static void DeleteProgressFile() 79 | { 80 | DeleteLocalFile(".progressfile"); 81 | } 82 | 83 | public static bool IsPathExist(string path) 84 | { 85 | return File.Exists(path) || Directory.Exists(path); 86 | } 87 | 88 | public static bool IsContainsSubDirectory(string path) 89 | { 90 | DirectoryInfo directory = new DirectoryInfo(path); 91 | foreach (var child in directory.EnumerateFileSystemInfos()) 92 | { 93 | if (child is DirectoryInfo) 94 | { 95 | return true; 96 | } 97 | } 98 | return false; 99 | } 100 | 101 | public static void DeleteLocalFile(string path) 102 | { 103 | if (File.Exists(path)) 104 | { 105 | File.Delete(path); 106 | } 107 | } 108 | 109 | public static void DeleteLocalFolder(string path) 110 | { 111 | if (Directory.Exists(path)) 112 | { 113 | DirectoryInfo directory = new DirectoryInfo(path); 114 | DeleteLocalItemRecursive(directory); 115 | } 116 | } 117 | 118 | private static void DeleteLocalItemRecursive(FileSystemInfo source) 119 | { 120 | if (source is DirectoryInfo) 121 | { 122 | foreach (var child in (source as DirectoryInfo).EnumerateFileSystemInfos()) 123 | { 124 | DeleteLocalItemRecursive(child); 125 | } 126 | } 127 | 128 | source.Delete(); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /ShareFileSnapIn/AuthenticationDomain.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace ShareFile.Api.Powershell 5 | { 6 | public class AuthenticationDomain 7 | { 8 | public string Id { get; set; } 9 | 10 | public bool IsDefault { get; set; } 11 | 12 | public string Provider { get; set; } 13 | 14 | public string Entity { get; set; } 15 | 16 | /// 17 | /// List of known ShareFile domains. These are checked to allow splitting of 18 | /// URLs into account + TLD; which can't be done otherwise. 19 | /// 20 | private string[] ShareFileDomains = new string[] 21 | { 22 | "sf-api.com", "sharefile.com", "sf-apitest.com", "sharefiletest.com", 23 | "sf-apidev.com", "sharefiledev.com", "citrixdata.com", "sharefile.eu", 24 | "sf-api.eu", "securevdr.com" 25 | }; 26 | 27 | public string Uri 28 | { 29 | get 30 | { 31 | if (Domain != null && Provider != null && ApiVersion != null) 32 | { 33 | string accountDomainRoot = !string.IsNullOrEmpty(Account) ? string.Format("{0}.{1}", Account, Domain) : Domain; 34 | if (!string.IsNullOrEmpty(Root)) accountDomainRoot += "/" + Root; 35 | return string.Format("https://{0}/{1}/{2}", accountDomainRoot, Provider, ApiVersion); 36 | } 37 | else return null; 38 | } 39 | set 40 | { 41 | Domain = null; 42 | Uri uri = new Uri(value); 43 | // Domain for sharefile accounts is account.domain 44 | // Domain for connectors do not have the account split 45 | foreach (var domain in ShareFileDomains) 46 | { 47 | if (uri.Host.EndsWith(domain)) 48 | { 49 | Domain = domain; 50 | Account = uri.Host.Substring(0, uri.Host.Length - domain.Length - 1); 51 | } 52 | } 53 | if (Domain == null) Domain = uri.Authority; 54 | 55 | // Parts are /// 56 | // The Uri may contain extra parts, if the caller passes something like /sf/v3/Items (which contains the Entity) 57 | // We break-down the parts from back to front, using v as the identifier for version 58 | string[] parts = uri.Segments; 59 | int idx = parts.Length - 1; 60 | while (idx >= 0) 61 | { 62 | if (parts[idx].StartsWith("v")) 63 | { 64 | ApiVersion = parts[idx--]; 65 | if (ApiVersion.EndsWith("/")) ApiVersion = ApiVersion.Substring(0, ApiVersion.Length - 1); 66 | if (idx < 0) throw new Exception("Invalid ShareFile URI - missing provider"); 67 | Provider = parts[idx].Substring(0, parts[idx].Length - 1); 68 | if (idx > parts.Length - 1) Entity = parts[idx + 1]; 69 | idx--; 70 | break; 71 | } 72 | idx--; 73 | } 74 | if (idx >= 0) 75 | { 76 | for (int i = 0; i <= idx; i++) 77 | { 78 | if (parts[i] != "/") Root += parts[i]; 79 | } 80 | } 81 | } 82 | } 83 | 84 | public string Account 85 | { 86 | get { return _account; } 87 | set { _account = value != null ? value.ToLower() : null; } 88 | } 89 | private string _account; 90 | 91 | public string Domain 92 | { 93 | get { return _domain; } 94 | set { _domain = value != null ? value.ToLower() : null; } 95 | } 96 | private string _domain; 97 | 98 | public string Root 99 | { 100 | get { return _root; } 101 | set { _root = value != null ? value.ToLower() : null; } 102 | } 103 | private string _root; 104 | 105 | public string ApiVersion 106 | { 107 | get { return _apiVersion; } 108 | set { _apiVersion = value != null ? value.ToLower() : null; } 109 | } 110 | private string _apiVersion; 111 | 112 | public string OAuthToken { get; set; } 113 | 114 | public string OAuthRefreshToken { get; set; } 115 | 116 | public string AuthID { get; set; } 117 | 118 | public NetworkCredential Credential { get; set; } 119 | 120 | public bool IsApiUri 121 | { 122 | get 123 | { 124 | return ApiVersion != null && Provider != null && Entity != null && Domain != null; 125 | } 126 | } 127 | 128 | public bool IsShareFileUri 129 | { 130 | get 131 | { 132 | return Provider.Equals("sf"); 133 | } 134 | } 135 | 136 | public string Username { get; set; } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /Test-ShareFileSnapIn/Test-ShareFileSnapIn.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {95E10D74-0853-4701-A8E3-F1B391E019A0} 7 | Library 8 | Properties 9 | Test_ShareFileSnapIn 10 | Test-ShareFileSnapIn 11 | v4.8 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | false 30 | 31 | 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE 36 | prompt 37 | 4 38 | false 39 | 40 | 41 | 42 | 43 | 3.5 44 | 45 | 46 | False 47 | C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | Always 74 | 75 | 76 | Always 77 | 78 | 79 | 80 | 81 | {db7fd2e6-2884-4e66-bfd8-219c007da4cb} 82 | ShareFileSnapIn 83 | 84 | 85 | 86 | 87 | 88 | 89 | False 90 | 91 | 92 | False 93 | 94 | 95 | False 96 | 97 | 98 | False 99 | 100 | 101 | 102 | 103 | 104 | 105 | 112 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Resume/ResumeSupport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | using ShareFile.Api.Powershell.Properties; 9 | 10 | namespace ShareFile.Api.Powershell.Resume 11 | { 12 | /// 13 | /// ResumeSupport class to facilitate the resume last Copy-SfItem command if failed somehow 14 | /// It will use ".progressfile" file to keep track of current command and successfully copied files 15 | /// If command breaks and failed to complete due to disconnection then on next copy operation it will check progress file and prompt user 16 | /// 17 | class ResumeSupport 18 | { 19 | private String XML_FILE_NAME = @".progressfile"; 20 | private ProgressFile progressObject; 21 | private bool flagResume; 22 | 23 | /// 24 | /// Initialize/Load the progressfile and de-serialize the object 25 | /// 26 | public ResumeSupport() 27 | { 28 | 29 | string directory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 30 | XML_FILE_NAME = Path.Combine(directory, Resources.AppName, XML_FILE_NAME); 31 | flagResume = true; 32 | progressObject = LoadFile(); 33 | } 34 | 35 | /// 36 | /// Starting a new Copy command 37 | /// 38 | /// Source Paths 39 | /// Destination Path 40 | /// Force Replace 41 | /// Upload Specification Request Details 42 | public void Start(String[] source, String target, bool force, String details) 43 | { 44 | progressObject = new ProgressFile(); 45 | 46 | progressObject.ArgumentSource = source; 47 | progressObject.ArgumentTarget = target; 48 | progressObject.ArgumentForce = force; 49 | progressObject.ArgumentDetails = details; 50 | 51 | SaveFile(progressObject); 52 | } 53 | 54 | /// 55 | /// Mark file as complete (copy done) 56 | /// 57 | /// File Name 58 | public void MarkFileStatus(String fileName) 59 | { 60 | progressObject.CompletedFiles.Add(fileName); 61 | progressObject.IsPending = true; 62 | 63 | SaveFile(progressObject); 64 | } 65 | 66 | /// 67 | /// Check the file status if copying complete or not 68 | /// 69 | /// File Name 70 | /// True if file is succssfully copied 71 | public bool CheckFileStatus(String fileName) 72 | { 73 | return progressObject.CompletedFiles.Contains(fileName); 74 | } 75 | 76 | /// 77 | /// Command is completed 78 | /// Clean up the .progressfile and mark it completed 79 | /// 80 | public void End() 81 | { 82 | progressObject.CompletedFiles = new System.Collections.ArrayList(); 83 | progressObject.IsPending = false; 84 | 85 | SaveFile(progressObject); 86 | } 87 | 88 | /// 89 | /// Check if last execution is completed or disconnected 90 | /// 91 | public bool IsPending 92 | { 93 | get 94 | { 95 | return flagResume && progressObject.IsExist && progressObject.IsPending; 96 | } 97 | } 98 | 99 | /// 100 | /// Get source path 101 | /// 102 | public String[] GetPath 103 | { 104 | get 105 | { 106 | return progressObject.ArgumentSource; 107 | } 108 | } 109 | 110 | /// 111 | /// Get destination path 112 | /// 113 | public String GetDestination 114 | { 115 | get 116 | { 117 | return progressObject.ArgumentTarget; 118 | } 119 | } 120 | 121 | /// 122 | /// Get fource argument 123 | /// 124 | public bool GetForce 125 | { 126 | get 127 | { 128 | return progressObject.ArgumentForce; 129 | } 130 | } 131 | 132 | /// 133 | /// Get details argument 134 | /// 135 | public String GetDetails 136 | { 137 | get 138 | { 139 | return progressObject.ArgumentDetails; 140 | } 141 | } 142 | 143 | public void UnmarkResumeFlag() 144 | { 145 | this.flagResume = false; 146 | } 147 | 148 | /// 149 | /// Save/serialize progress to ".progressfile" file 150 | /// It will be called after each operation i.e. file completion, command completion & new command 151 | /// 152 | /// Process file object 153 | private void SaveFile(ProgressFile progressObject) 154 | { 155 | SupportHandler.Save(progressObject, XML_FILE_NAME); 156 | } 157 | 158 | /// 159 | /// Load/de-serialize progress of command from ".progressfile" to and object 160 | /// 161 | /// ProgressFile object 162 | private ProgressFile LoadFile() 163 | { 164 | ProgressFile progressObject = new ProgressFile(); 165 | 166 | if (File.Exists(XML_FILE_NAME) == true) 167 | { 168 | progressObject = SupportHandler.Load(XML_FILE_NAME); 169 | progressObject.IsExist = true; 170 | } 171 | 172 | return progressObject; 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Browser/BasicAuthDialog.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Browser/OAuthAuthenticationForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Browser/OAuthAuthenticationForm.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Web.WebView2.Core; 2 | using ShareFile.Api.Powershell.Extensions; 3 | using ShareFile.Api.Powershell.Log; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Windows.Forms; 10 | 11 | namespace ShareFile.Api.Powershell.Browser 12 | { 13 | public partial class OAuthAuthenticationForm : Form 14 | { 15 | public delegate bool UrlEventCallback(Uri uri); 16 | private readonly Dictionary _urlEventHandlers = new Dictionary(); 17 | 18 | private readonly Dictionary _navigationIdToUrlMapping = new Dictionary(); 19 | 20 | private readonly CoreWebView2EnvironmentOptions webView2EnvOptions = new CoreWebView2EnvironmentOptions( 21 | additionalBrowserArguments: "--disable-features=msSmartScreenProtection", 22 | allowSingleSignOnUsingOSPrimaryAccount: true); 23 | 24 | public OAuthAuthenticationForm() 25 | { 26 | InitializeComponent(); 27 | 28 | InitializeWebView2(); 29 | } 30 | 31 | public void AddUrlEventHandler(string uri, UrlEventCallback handler) 32 | { 33 | _urlEventHandlers.Add(uri, handler); 34 | } 35 | 36 | public void Navigate(Uri uri) 37 | { 38 | webViewBrowser.CoreWebView2.Navigate(uri.ToString()); 39 | ShowDialog(); 40 | } 41 | 42 | private void InitializeWebView2() 43 | { 44 | // Select the cache directory 45 | string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); 46 | string cacheFolder = Path.Combine(localAppData, "ShareFile", "ShareFile PowerShell SDK"); 47 | 48 | var env = TaskHelper.RunSynchronously(CoreWebView2Environment.CreateAsync(null, cacheFolder, webView2EnvOptions)); 49 | 50 | TaskHelper.RunSynchronously(webViewBrowser.EnsureCoreWebView2Async(env)); 51 | 52 | webViewBrowser.CoreWebView2.ProcessFailed += CoreWebView2_ProcessFailed; 53 | webViewBrowser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false; 54 | webViewBrowser.CoreWebView2.Settings.AreDevToolsEnabled = false; 55 | webViewBrowser.CoreWebView2.Settings.AreBrowserAcceleratorKeysEnabled = false; 56 | webViewBrowser.CoreWebView2.ClientCertificateRequested += CoreWebView2_ClientCertificateRequested; 57 | 58 | webViewBrowser.NavigationStarting += WebViewBrowser_NavigationStarting; 59 | webViewBrowser.NavigationCompleted += WebViewBrowser_NavigationCompleted; 60 | } 61 | 62 | private void CoreWebView2_ClientCertificateRequested(object sender, CoreWebView2ClientCertificateRequestedEventArgs e) 63 | { 64 | var certificateList = e.MutuallyTrustedCertificates; 65 | 66 | if (certificateList.Count() == 1) 67 | { 68 | // If there is only one client certificate, then just use that one instead of prompting the user to click on it. 69 | e.SelectedCertificate = certificateList[0]; 70 | e.Handled = true; 71 | } 72 | } 73 | 74 | private void CoreWebView2_ProcessFailed(object sender, CoreWebView2ProcessFailedEventArgs e) 75 | { 76 | LogProcessFailedEventArgs(e); 77 | } 78 | 79 | private void LogProcessFailedEventArgs(CoreWebView2ProcessFailedEventArgs e) 80 | { 81 | Logger.Instance.Error($"WebView2 process failed: Reason: {e.Reason} Exit code: {e.ExitCode} ProcessFailedKind: {e.ProcessFailedKind} Process description: {e.ProcessDescription}"); 82 | if ((e.FrameInfosForFailedProcess?.Any()).GetValueOrDefault()) 83 | { 84 | var sb = new StringBuilder("FrameInfos"); 85 | foreach (var frameInfo in e.FrameInfosForFailedProcess) 86 | { 87 | sb.AppendFormat("\tName: {0}, Source: {1} ({2})", frameInfo.Name, frameInfo.Source, frameInfo.ToString()); 88 | sb.AppendLine(); 89 | } 90 | Logger.Instance.Error(sb.ToString()); 91 | } 92 | } 93 | 94 | private void WebViewBrowser_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e) 95 | { 96 | _navigationIdToUrlMapping[e.NavigationId] = e.Uri; 97 | } 98 | 99 | private void WebViewBrowser_NavigationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs e) 100 | { 101 | if (_navigationIdToUrlMapping.TryGetValue(e.NavigationId, out var url)) 102 | { 103 | foreach (var handler in _urlEventHandlers) 104 | { 105 | if (url.ToString().StartsWith(handler.Key)) 106 | { 107 | if (handler.Value.Invoke(new Uri(url))) 108 | { 109 | this.Close(); 110 | } 111 | } 112 | } 113 | _navigationIdToUrlMapping.Remove(e.NavigationId); 114 | } 115 | } 116 | 117 | private void ClearWebView2Cache() 118 | { 119 | var task = webViewBrowser?.CoreWebView2?.Profile?.ClearBrowsingDataAsync(); 120 | if (task != null) 121 | { 122 | TaskHelper.RunSynchronously(task); 123 | } 124 | } 125 | 126 | protected override void OnClosed(EventArgs e) 127 | { 128 | ClearWebView2Cache(); 129 | if (webViewBrowser != null) 130 | { 131 | if (webViewBrowser.CoreWebView2 != null) 132 | { 133 | webViewBrowser.CoreWebView2.ProcessFailed -= CoreWebView2_ProcessFailed; 134 | webViewBrowser.CoreWebView2.ClientCertificateRequested -= CoreWebView2_ClientCertificateRequested; 135 | } 136 | 137 | webViewBrowser.NavigationStarting -= WebViewBrowser_NavigationStarting; 138 | webViewBrowser.NavigationCompleted -= WebViewBrowser_NavigationCompleted; 139 | } 140 | base.OnClosed(e); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Samples/BackupShareFileAccount.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # BackupShareFileAccount.ps1 3 | # 4 | # Download an entire ShareFile account to a local directory. 5 | # 6 | # 7 | # Local Directory Structure: 8 | # 9 | # Local Directory 10 | # │ log-.txt 11 | # │ account-.csv 12 | # │ employees-.csv 13 | # │ sharedfolders-.csv 14 | # │ 15 | # └───Users 16 | # │ │ 17 | # │ └───user@email.com 18 | # │ │ 'Home Folder Name' 19 | # │ └─ ... 20 | # │ 21 | # └───Shared Folders 22 | # │ folder 23 | # │ ... 24 | # 25 | # 26 | # Requirements: 27 | # PowerShell 5 28 | # The latest PowerShell SDK for ShareFile: https://github.com/citrix/ShareFile-PowerShell 29 | # A Superuser for the ShareFile account: https://support.citrix.com/article/CTX208527 30 | # 31 | # Usage: 32 | # .\BackupShareFileAccount.ps1; Backup-ShareFileAccount -Type Shared -Path -Email -Subdomain 33 | # 34 | # Type: Full, Users 35 | # Path: The local path to backup to 36 | # Email: A superuser account email 37 | # Subdomain: The account subdomain 38 | # 39 | 40 | Add-PSSnapin ShareFile 41 | $global:BackupPath = $null 42 | $global:SFClient = $null 43 | 44 | function Backup-ShareFileAccount { 45 | [CmdletBinding(DefaultParameterSetName = "RequiredSet")] 46 | param( 47 | [Parameter(Mandatory,ParameterSetName = "RequiredSet")] 48 | [ValidateSet("Shared","Users","Full")] 49 | [string]$Type, 50 | [Parameter(Mandatory,ParameterSetName = "RequiredSet")] 51 | [string]$Path, 52 | [Parameter(Mandatory,ParameterSetName = "RequiredSet")] 53 | [string]$Email, 54 | [Parameter(Mandatory,ParameterSetName = "RequiredSet")] 55 | [string]$Subdomain 56 | ) 57 | 58 | $global:BackupPath = $Path 59 | $SFClientPath = $Path + "\" + $Email + ".sfps" 60 | 61 | if ([System.IO.File]::Exists($SFClientPath)) { 62 | Write-Host $SFClientPath " was found." -BackgroundColor Green -ForegroundColor DarkBlue 63 | $global:SFClient = Get-SFClient -Name $SFClientPath 64 | # Check validity 65 | if($?){ 66 | $(Send-SfRequest $SFClient -Entity Accounts) 2>&1 | out-null 67 | } else { 68 | Write-Host "Saved client file is invalid. Please sign in." -BackgroundColor Yellow -ForegroundColor DarkBlue 69 | New-SfClient -Name $SFClientPath -Account $Subdomain 70 | $global:SFClient = Get-SFClient -Name $SFClientPath 71 | } 72 | } else { 73 | Write-Host $SFClientPath " was NOT found. Please sign in." -BackgroundColor Yellow -ForegroundColor DarkBlue 74 | New-SfClient -Name $SFClientPath -Account $Subdomain 75 | $global:SFClient = Get-SFClient -Name $SFClientPath 76 | } 77 | 78 | Log "A $Type backup was requested by $Email." 79 | $AccountInfo = Send-SfRequest -Client $SFClient -Method GET -Entity Accounts -select "CompanyName,subdomain,Id" | Select-Object -Property CompanyName,subdomain,Id 80 | $AccountInfo | Export-Csv -Path $BackupPath/account-$("{0:yyyyMMdd}" -f (Get-Date)).csv -NoTypeInformation 81 | 82 | switch ($Type) { 83 | "Shared" { Backup-SharedFolders -SFClient $SFClient } 84 | "Users" { Backup-Users -SFClient $SFClient } 85 | "Full" { Backup-Full -SFClient $SFClient } 86 | } 87 | } 88 | 89 | function Backup-Full { 90 | param( 91 | [Parameter(Mandatory)] 92 | [ShareFile.Api.Powershell.PSShareFileClient]$SFClient 93 | ) 94 | 95 | Log "Initiated Backup-Full function." 96 | Backup-Users -SFClient $SFClient 97 | Backup-SharedFolders -SFClient $SFClient 98 | 99 | } 100 | 101 | function Backup-SharedFolders { 102 | param( 103 | [Parameter(Mandatory)] 104 | [ShareFile.Api.Powershell.PSShareFileClient]$SFClient 105 | ) 106 | 107 | Log "Initiated Backup-SharedFolders function." 108 | $sharedfolders = Send-SfRequest -Client $SFClient -Method GET -Entity Items -Id "allshared" -Expand "Children" | Select-object -ExpandProperty Children 109 | $sharedfolders | Select-Object -Property Name,Id | Export-Csv -Path $BackupPath/sharedfolders-$("{0:yyyyMMdd}" -f (Get-Date)).csv -NoTypeInformation 110 | 111 | # Local Folder Structure and Download 112 | $SharedPath = "$BackupPath/Shared Folders" 113 | if (!(Test-Path $SharedPath)) { New-Item -Path $SharedPath -Type Directory } 114 | foreach ($sharedfolder in $sharedfolders) { 115 | $Root = "$($sharedfolder.Id):/" + "$($sharedfolder.Name)" 116 | $LocalPath = "$SharedPath/" 117 | Backup-ChildItems -Root $Root -LocalPath $LocalPath -DriveId $($sharedfolder.Id) -SFClient $SFClient 118 | } 119 | 120 | Log "Shared Folders backup completed." 121 | } 122 | 123 | function Backup-Users { 124 | param( 125 | [Parameter(Mandatory)] 126 | [ShareFile.Api.Powershell.PSShareFileClient]$SFClient 127 | ) 128 | 129 | Log "Initiated Backup-Users function." 130 | $Employees = Send-SfRequest -Client $SFClient -Method GET -Entity Accounts/Employees -select "Id,Email" 131 | $Employees | Select-Object -Property Email,Id | Export-Csv -Path $BackupPath/employees-$("{0:yyyyMMdd}" -f (Get-Date)).csv -NoTypeInformation 132 | 133 | # Local Folder Structure & Download 134 | $UsersPath = "$BackupPath/Users" 135 | if (!(Test-Path $UsersPath)) { New-Item -Path $UsersPath -Type Directory } 136 | foreach ($Employee in $Employees) { 137 | if (!(Test-Path "$UsersPath/$($Employee.Email)")) { New-Item -Path "$UsersPath/$($Employee.Email)" -Type Directory } 138 | $Root = "$($Employee.Id):/" + (Send-SfRequest $SFClient -Entity "Users($($Employee.Id))/HomeFolder").Name 139 | $LocalPath = "$UsersPath/$($Employee.Email)/" 140 | Backup-ChildItems -Root $Root -LocalPath $LocalPath -DriveId $($Employee.Id) -SFClient $SFClient 141 | } 142 | 143 | Log "User backup completed." 144 | } 145 | 146 | function Backup-ChildItems { 147 | param( 148 | [Parameter(Mandatory)] 149 | [ShareFile.Api.Powershell.PSShareFileClient]$SFClient, 150 | [Parameter(Mandatory)] 151 | [string]$Root, 152 | [Parameter(Mandatory)] 153 | [string]$LocalPath, 154 | [Parameter(Mandatory)] 155 | [string]$DriveId 156 | ) 157 | New-PSDrive -Name $DriveId -PSProvider ShareFile -Client $SFClient -Root "/" 158 | Copy-SfItem -Path $Root -Destination $LocalPath 159 | Remove-PSDrive $DriveId 160 | } 161 | 162 | function Log { 163 | param( 164 | [Parameter(Mandatory=$true)][String]$msg 165 | ) 166 | $LogFileDate = "{0:yyyyMMdd}" -f (Get-Date) 167 | $LogTime = "[{0:MM/dd/yy} {0:HH:mm:ss}] " -f (Get-Date) 168 | Add-Content $BackupPath/log-$LogFileDate.txt ($LogTime + $msg) 169 | } 170 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Browser/BasicAuthDialog.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ShareFile.Api.Powershell.Browser 2 | { 3 | partial class BasicAuthDialog 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.labelDomain = new System.Windows.Forms.Label(); 32 | this.labelUsername = new System.Windows.Forms.Label(); 33 | this.labelPassword = new System.Windows.Forms.Label(); 34 | this.textBoxUsername = new System.Windows.Forms.TextBox(); 35 | this.buttonCancel = new System.Windows.Forms.Button(); 36 | this.buttonOK = new System.Windows.Forms.Button(); 37 | this.textBoxPassword = new System.Windows.Forms.TextBox(); 38 | this.labelDomainName = new System.Windows.Forms.Label(); 39 | this.SuspendLayout(); 40 | // 41 | // labelDomain 42 | // 43 | this.labelDomain.AutoSize = true; 44 | this.labelDomain.Location = new System.Drawing.Point(13, 13); 45 | this.labelDomain.Name = "labelDomain"; 46 | this.labelDomain.Size = new System.Drawing.Size(141, 13); 47 | this.labelDomain.TabIndex = 0; 48 | this.labelDomain.Text = "Enter credentials for domain:"; 49 | // 50 | // labelUsername 51 | // 52 | this.labelUsername.AutoSize = true; 53 | this.labelUsername.Location = new System.Drawing.Point(13, 73); 54 | this.labelUsername.Name = "labelUsername"; 55 | this.labelUsername.Size = new System.Drawing.Size(58, 13); 56 | this.labelUsername.TabIndex = 1; 57 | this.labelUsername.Text = "Username:"; 58 | // 59 | // labelPassword 60 | // 61 | this.labelPassword.AutoSize = true; 62 | this.labelPassword.Location = new System.Drawing.Point(16, 104); 63 | this.labelPassword.Name = "labelPassword"; 64 | this.labelPassword.Size = new System.Drawing.Size(56, 13); 65 | this.labelPassword.TabIndex = 2; 66 | this.labelPassword.Text = "Password:"; 67 | // 68 | // textBoxUsername 69 | // 70 | this.textBoxUsername.Location = new System.Drawing.Point(78, 69); 71 | this.textBoxUsername.Name = "textBoxUsername"; 72 | this.textBoxUsername.Size = new System.Drawing.Size(227, 20); 73 | this.textBoxUsername.TabIndex = 1; 74 | // 75 | // buttonCancel 76 | // 77 | this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; 78 | this.buttonCancel.Location = new System.Drawing.Point(230, 144); 79 | this.buttonCancel.Name = "buttonCancel"; 80 | this.buttonCancel.Size = new System.Drawing.Size(75, 23); 81 | this.buttonCancel.TabIndex = 4; 82 | this.buttonCancel.Text = "Cancel"; 83 | this.buttonCancel.UseVisualStyleBackColor = true; 84 | this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); 85 | // 86 | // buttonOK 87 | // 88 | this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK; 89 | this.buttonOK.Location = new System.Drawing.Point(149, 144); 90 | this.buttonOK.Name = "buttonOK"; 91 | this.buttonOK.Size = new System.Drawing.Size(75, 23); 92 | this.buttonOK.TabIndex = 3; 93 | this.buttonOK.Text = "OK"; 94 | this.buttonOK.UseVisualStyleBackColor = true; 95 | this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); 96 | // 97 | // textBoxPassword 98 | // 99 | this.textBoxPassword.Location = new System.Drawing.Point(78, 101); 100 | this.textBoxPassword.Name = "textBoxPassword"; 101 | this.textBoxPassword.PasswordChar = '*'; 102 | this.textBoxPassword.Size = new System.Drawing.Size(227, 20); 103 | this.textBoxPassword.TabIndex = 2; 104 | // 105 | // labelDomainName 106 | // 107 | this.labelDomainName.AutoSize = true; 108 | this.labelDomainName.Location = new System.Drawing.Point(12, 37); 109 | this.labelDomainName.Name = "labelDomainName"; 110 | this.labelDomainName.Size = new System.Drawing.Size(19, 13); 111 | this.labelDomainName.TabIndex = 0; 112 | this.labelDomainName.Text = "__"; 113 | // 114 | // BasicAuthDialog 115 | // 116 | this.AcceptButton = this.buttonOK; 117 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 118 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 119 | this.CancelButton = this.buttonCancel; 120 | this.ClientSize = new System.Drawing.Size(320, 172); 121 | this.Controls.Add(this.textBoxPassword); 122 | this.Controls.Add(this.buttonOK); 123 | this.Controls.Add(this.buttonCancel); 124 | this.Controls.Add(this.textBoxUsername); 125 | this.Controls.Add(this.labelPassword); 126 | this.Controls.Add(this.labelUsername); 127 | this.Controls.Add(this.labelDomainName); 128 | this.Controls.Add(this.labelDomain); 129 | this.Name = "BasicAuthDialog"; 130 | this.Text = "ShareFile Authentication"; 131 | this.ResumeLayout(false); 132 | this.PerformLayout(); 133 | 134 | } 135 | 136 | #endregion 137 | 138 | private System.Windows.Forms.Label labelDomain; 139 | private System.Windows.Forms.Label labelUsername; 140 | private System.Windows.Forms.Label labelPassword; 141 | private System.Windows.Forms.TextBox textBoxUsername; 142 | private System.Windows.Forms.Button buttonCancel; 143 | private System.Windows.Forms.Button buttonOK; 144 | private System.Windows.Forms.TextBox textBoxPassword; 145 | private System.Windows.Forms.Label labelDomainName; 146 | } 147 | } -------------------------------------------------------------------------------- /ShareFileSnapIn-Installer-x32/Product.wxs: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | = "2.0" AND POWERSHELL3VERSION >= "4.0")]]> 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 54 | 55 | 56 | 57 | 58 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /Test-ShareFileSnapIn/CopySFItemsTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.ObjectModel; 4 | using System.IO; 5 | using System.Management.Automation; 6 | using System.Management.Automation.Runspaces; 7 | using Microsoft.VisualStudio.TestTools.UnitTesting; 8 | using ShareFile.Api.Powershell; 9 | 10 | namespace Test_ShareFileSnapIn 11 | { 12 | [TestClass] 13 | public class CopySFItemsTests 14 | { 15 | private PSObject sfLogin = null; 16 | Runspace runspace = null; 17 | 18 | [TestInitialize] 19 | public void InitializeTests() 20 | { 21 | RunspaceConfiguration config = RunspaceConfiguration.Create(); 22 | 23 | PSSnapInException warning; 24 | 25 | config.AddPSSnapIn("ShareFile", out warning); 26 | 27 | runspace = RunspaceFactory.CreateRunspace(config); 28 | runspace.Open(); 29 | 30 | // do login first to start tests 31 | using (Pipeline pipeline = runspace.CreatePipeline()) 32 | { 33 | 34 | Command command = new Command("Get-SfClient"); 35 | command.Parameters.Add(new CommandParameter("Name", Utils.LoginFilePath)); 36 | 37 | pipeline.Commands.Add(command); 38 | 39 | Collection psObjects = pipeline.Invoke(); 40 | Assert.AreEqual(1, psObjects.Count); 41 | sfLogin = psObjects[0]; 42 | } 43 | 44 | using (Pipeline pipeline = runspace.CreatePipeline()) 45 | { 46 | Command command = new Command("New-PSDrive"); 47 | command.Parameters.Add("Name", Utils.ShareFileDriveLetter); 48 | command.Parameters.Add("PSProvider", "ShareFile"); 49 | command.Parameters.Add("Root", "/"); 50 | command.Parameters.Add("Client", sfLogin); 51 | 52 | pipeline.Commands.Add(command); 53 | 54 | Collection psObjects = pipeline.Invoke(); 55 | 56 | // Drive is successfully mapped to root folder 57 | Assert.AreEqual(1, psObjects.Count); 58 | } 59 | } 60 | 61 | [TestMethod] 62 | public void TM1_CopyItemToLocalTest() 63 | { 64 | using (Pipeline pipeline = runspace.CreatePipeline()) 65 | { 66 | Utils.DeleteLocalFile(Utils.LocalFileDownloaded); 67 | Utils.DeleteProgressFile(); 68 | 69 | Command command = new Command("Copy-SFItem"); 70 | command.Parameters.Add("Path", Utils.ShareFileFileFullPath); 71 | command.Parameters.Add("Destination", Utils.LocalBaseFolder); 72 | 73 | pipeline.Commands.Add(command); 74 | 75 | Collection psObjects = pipeline.Invoke(); 76 | 77 | Assert.AreEqual(1, psObjects.Count); 78 | Assert.IsTrue(Utils.IsPathExist(Utils.LocalFileDownloaded)); 79 | } 80 | } 81 | 82 | [TestMethod] 83 | public void TM2_CopyItemToLocalForceTest() 84 | { 85 | using (Pipeline pipeline = runspace.CreatePipeline()) 86 | { 87 | Utils.DeleteProgressFile(); 88 | 89 | Command command = new Command("Copy-SFItem"); 90 | command.Parameters.Add("Path", Utils.ShareFileFileFullPath); 91 | command.Parameters.Add("Destination", Utils.LocalBaseFolder); 92 | command.Parameters.Add("Force", true); 93 | 94 | pipeline.Commands.Add(command); 95 | 96 | Collection psObjects = pipeline.Invoke(); 97 | Assert.AreEqual(1, psObjects.Count); 98 | } 99 | } 100 | 101 | [TestMethod] 102 | public void TM3_CopyItemToShareFileServerTest() 103 | { 104 | using (Pipeline pipeline = runspace.CreatePipeline()) 105 | { 106 | Utils.DeleteProgressFile(); 107 | 108 | Command command = new Command("Copy-SFItem"); 109 | command.Parameters.Add("Path", Utils.LocalFile); 110 | command.Parameters.Add("Destination", Utils.ShareFileHomeFolder); 111 | 112 | // remove line after adding cleanup script to sharefile server 113 | command.Parameters.Add("Force", true); 114 | 115 | pipeline.Commands.Add(command); 116 | 117 | Collection psObjects = pipeline.Invoke(); 118 | Assert.AreEqual(1, psObjects.Count); 119 | } 120 | 121 | using (Pipeline pipeline = runspace.CreatePipeline()) 122 | { 123 | Command command = new Command("Get-ChildItem"); 124 | 125 | pipeline.Commands.Add(command); 126 | 127 | pipeline.Input.Write(Utils.ShareFileFileUploaded); 128 | Collection psObjects = pipeline.Invoke(); 129 | 130 | Assert.AreEqual(1, psObjects.Count); 131 | Assert.AreEqual("ShareFile.Api.Client.Models.File", psObjects[0].BaseObject.ToString()); 132 | } 133 | } 134 | 135 | [TestMethod] 136 | public void TM4_CopyItemToShareFileServerForceTest() 137 | { 138 | using (Pipeline pipeline = runspace.CreatePipeline()) 139 | { 140 | Utils.DeleteProgressFile(); 141 | 142 | Command command = new Command("Copy-SFItem"); 143 | command.Parameters.Add("Path", Utils.LocalFile); 144 | command.Parameters.Add("Destination", Utils.ShareFileHomeFolder); 145 | command.Parameters.Add("Force", true); 146 | 147 | pipeline.Commands.Add(command); 148 | 149 | Collection psObjects = pipeline.Invoke(); 150 | Assert.AreEqual(1, psObjects.Count); 151 | } 152 | 153 | using (Pipeline pipeline = runspace.CreatePipeline()) 154 | { 155 | Command command = new Command("Get-ChildItem"); 156 | 157 | pipeline.Commands.Add(command); 158 | 159 | pipeline.Input.Write(Utils.ShareFileFileUploaded); 160 | Collection psObjects = pipeline.Invoke(); 161 | 162 | Assert.AreEqual(1, psObjects.Count); 163 | Assert.AreEqual("ShareFile.Api.Client.Models.File", psObjects[0].BaseObject.ToString()); 164 | } 165 | } 166 | 167 | [TestMethod] 168 | public void TM5_CopyItemToShareFileWildCardTest() 169 | { 170 | using (Pipeline pipeline = runspace.CreatePipeline()) 171 | { 172 | Utils.DeleteProgressFile(); 173 | 174 | Command command = new Command("Copy-SFItem"); 175 | command.Parameters.Add("Path", Utils.LocalFolder + @"\*.*"); 176 | command.Parameters.Add("Destination", Utils.ShareFileHomeFolder); 177 | 178 | // remove line after adding cleanup script to sharefile server 179 | command.Parameters.Add("Force", true); 180 | 181 | pipeline.Commands.Add(command); 182 | 183 | Collection psObjects = pipeline.Invoke(); 184 | Assert.AreEqual(1, psObjects.Count); 185 | } 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ShareFile.Api.Powershell.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ShareFile.Api.Powershell.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to ShareFile. 65 | /// 66 | internal static string AppName { 67 | get { 68 | return ResourceManager.GetString("AppName", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to IOdm0AhEu7RclDqhC5vKtpcyyJrdcGSK. 74 | /// 75 | internal static string ClientId { 76 | get { 77 | return ResourceManager.GetString("ClientId", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to 8VR4WXDZ30CThAyo9cnXaDeC2xyFP5e1wDKPujYrpBfGmtXy. 83 | /// 84 | internal static string ClientSecret { 85 | get { 86 | return ResourceManager.GetString("ClientSecret", resourceCulture); 87 | } 88 | } 89 | 90 | /// 91 | /// Looks up a localized string similar to sf-api.com. 92 | /// 93 | internal static string DefaultApiDomain { 94 | get { 95 | return ResourceManager.GetString("DefaultApiDomain", resourceCulture); 96 | } 97 | } 98 | 99 | /// 100 | /// Looks up a localized string similar to v3. 101 | /// 102 | internal static string DefaultApiVersion { 103 | get { 104 | return ResourceManager.GetString("DefaultApiVersion", resourceCulture); 105 | } 106 | } 107 | 108 | /// 109 | /// Looks up a localized string similar to secure. 110 | /// 111 | internal static string DefaultGlobalApiSubdomain { 112 | get { 113 | return ResourceManager.GetString("DefaultGlobalApiSubdomain", resourceCulture); 114 | } 115 | } 116 | 117 | /// 118 | /// Looks up a localized string similar to NLog.config. 119 | /// 120 | internal static string LogConfigFile { 121 | get { 122 | return ResourceManager.GetString("LogConfigFile", resourceCulture); 123 | } 124 | } 125 | 126 | /// 127 | /// Looks up a localized string similar to main.log. 128 | /// 129 | internal static string LogFile { 130 | get { 131 | return ResourceManager.GetString("LogFile", resourceCulture); 132 | } 133 | } 134 | 135 | /// 136 | /// Looks up a localized string similar to 5. 137 | /// 138 | internal static string MaxExceptionRetry { 139 | get { 140 | return ResourceManager.GetString("MaxExceptionRetry", resourceCulture); 141 | } 142 | } 143 | 144 | /// 145 | /// Looks up a localized string similar to . 146 | /// 147 | internal static string ProgressFile { 148 | get { 149 | return ResourceManager.GetString("ProgressFile", resourceCulture); 150 | } 151 | } 152 | 153 | /// 154 | /// Looks up a localized string similar to https://secure.sharefile.com/oauth/oauthcomplete.aspx. 155 | /// 156 | internal static string RedirectURL { 157 | get { 158 | return ResourceManager.GetString("RedirectURL", resourceCulture); 159 | } 160 | } 161 | 162 | /// 163 | /// Looks up a localized string similar to sf. 164 | /// 165 | internal static string ShareFileProvider { 166 | get { 167 | return ResourceManager.GetString("ShareFileProvider", resourceCulture); 168 | } 169 | } 170 | 171 | /// 172 | /// Looks up a localized string similar to 1.9. 173 | /// 174 | internal static string Version { 175 | get { 176 | return ResourceManager.GetString("Version", resourceCulture); 177 | } 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | ShareFile 122 | 123 | 124 | IOdm0AhEu7RclDqhC5vKtpcyyJrdcGSK 125 | 126 | 127 | 8VR4WXDZ30CThAyo9cnXaDeC2xyFP5e1wDKPujYrpBfGmtXy 128 | 129 | 130 | sf-api.com 131 | 132 | 133 | v3 134 | 135 | 136 | secure 137 | 138 | 139 | NLog.config 140 | 141 | 142 | main.log 143 | 144 | 145 | 5 146 | 147 | 148 | 149 | 150 | 151 | https://secure.sharefile.com/oauth/oauthcomplete.aspx 152 | 153 | 154 | sf 155 | 156 | 157 | 1.9 158 | 159 | -------------------------------------------------------------------------------- /Samples/Monitor_Uploads_From_ShareFile_Queue_SYMC_DLP.ps1: -------------------------------------------------------------------------------- 1 | # Monitor_Uploads_From_ShareFile_Queue_SYMC_DLP.ps1 2 | # Script written by Cameron Erens & Brian Mathews 3 | # This example code is provided as-is. 4 | # Last Revised May 7, 2015 5 | # For full instructions, including configuration & dependencies please see 6 | # 'Setup Instructions to Monitor ShareFile Uploads to on-prem with Symantec DLP (v1.1).docx' 7 | # available at https://github.com/citrix/ShareFile-PowerShell/blob/master/Samples/Monitor_Uploads_From_ShareFile_Queue_SYMC_DLP_INSTRUCTIONS_1.1.docx 8 | # and also read through the comments in this code. 9 | 10 | 11 | Add-PSSnapin Microsoft.Exchange.Management.Powershell.Admin -erroraction silentlyContinue 12 | Add-PSSnapin ShareFile 13 | 14 | Import-Module 'C:\SymantecDLP\Protect\plugins\Disaster Recovery\Recovery.psm1' 15 | Import-Module 'C:\SymantecDLP\Protect\plugins\Disaster Recovery\LitJson.dll' 16 | 17 | $StoragePath = "\\StorageZone\ShareFileData\persistentstorage\sf-us-1\a0aa4f04-d303-45fa-aa66-6b958b44ec1e" 18 | $DropLocation = "\\detectionserver\C$\drop" 19 | 20 | # Get objects (qitems) from the Storage Zone's upload / av queue, and make an EML file out of each corresponding persistentstorage file 21 | # this qid is constant--always the same for the upload / av queue 22 | # please note that the storagezone url must be specified in the Recovery.psm file in the Disaster Recovery folder (Citrix ShareFile StorageZones libraries) 23 | $qid = "914DF171-825A-4E0A-B622-384C0778386F" 24 | $qitems = Get-SCQueueItem -qid $qid 25 | 26 | foreach ($qitem in $qitems) 27 | { 28 | $sfFilePath = $qitem.DataBlob.filepath 29 | # the $substr will be the file guid in persistentstorage 30 | $storageGuid = $sfFilePath.SubString($sfFilePath.indexOf("\") ) 31 | 32 | # ShareFile V3 api and StorageZones upload / av queue use dashes, but persistentstoage filenames 33 | # use underscores, so replace any dashes with underscores 34 | $storageGuid = $storageGuid.Replace("-","_") 35 | $storagefile = "$StoragePath$storageGuid" 36 | 37 | 38 | # look up additional file attributes from ShareFile regarding upload 39 | #$storageGuid = $storageGuid.Replace("-","_") 40 | 41 | # *** 42 | $FileID = $qitem.DataBlob.fileid 43 | Write-Host "File ID=$FileID" 44 | # *** 45 | 46 | # Now we need to log into ShareFile / use sfclient to pull the ShareFile item to get more metadata about the file 47 | 48 | $login = "C:\SymantecDLP\Protect\plugins\SFPS-login.sfps" 49 | # if the $login file does not exist or is invalid, then the lookup script will return only the 50 | # ShareFile file id, but no additional metadata 51 | 52 | 53 | $sfClient = get-SfClient -Name $login 54 | # could add some null check logic here to check whether a valid $sfClient was gotten successfully 55 | 56 | # Get the ShareFile file item by its ShareFile fileid 57 | $item = Send-SfRequest -Client $sfClient -Entity Items -id $qitem.DataBlob.fileid 58 | # could add some null check logic here to check and handle the case if specified ShareFile fileid was not found 59 | 60 | $name = $item.Name 61 | Write-Host "File Name=$name" 62 | 63 | $creationDate = $item.CreationDate 64 | Write-Host "Creation Date=$CreationDate" 65 | 66 | $CreatorName = $item.CreatorFirstName + " " + $item.CreatorLastName 67 | Write-Host "Creator=$CreatorName" 68 | 69 | #t his command returns a path of folder Ids which we need to parse to string names 70 | $folderPath = $item.Path.ToString() 71 | # remove first slash before split so it doesn't create empty string 72 | $fullPath = $folderPath.Substring(1).Split("/") 73 | $returnPath = "/" 74 | $count = 0 75 | # the returned path contains root and the account folder, which we do not need 76 | for ($x=2;$x-lt$fullPath.Count; $x++ ){ 77 | $pathItem = $fullPath[$x] 78 | #we want to grab the name of the folder in the path 79 | $tmpItem = Send-SfRequest -Client $sfClient -Entity Items -Id $pathItem 80 | $returnPath += $tmpItem.Name + "/" 81 | $count++ 82 | } 83 | $returnPath += $ParentItem.Name 84 | $ParentName = $returnPath 85 | Write-Host "Parent Folder=$ParentName" 86 | 87 | # need an 'Expand' call to get Creator email address: 88 | $itemWithCreator = Send-SfRequest -Client $sfClient -Entity Items -id $item.id -Expand Creator 89 | $CreatorEmail = $itemWithCreator.Creator.Email 90 | Write-Host "Creator Email=$CreatorEmail" 91 | 92 | # get direct folder link to parent folder 93 | $parentId = $item.Parent.Id 94 | $sfUrl = $item.url.ToString() 95 | $subdomain = $sfUrl.SubString(0,$sfUrl.IndexOf(".")) 96 | $link = "$subdomain.sharefile.com/f/$parentId" 97 | 98 | Write-Host "Direct Link to Parent Folder=$link" 99 | 100 | $FileSizeinKB = $item.FileSizeinKB 101 | $unit = "KB" 102 | if($fileSizeinKB -gt 1024*1024) 103 | { 104 | $unit = "GB" 105 | } 106 | elseif($fileSizeinKB -gt 1024) 107 | { 108 | $unit = "MB" 109 | } 110 | Write-Host "File Size=$FileSizeinKB $unit" 111 | 112 | # Creates EML message including this metadata, with file as attachment 113 | # this email message will be placed in drop folder so that Symantec DLP 114 | # scans the file and generates an DLP incident if a policy is violated 115 | $smtpClient = New-Object System.Net.Mail.SmtpClient 116 | $smtpClient.PickupDirectoryLocation = $DropLocation 117 | $smtpClient.DeliveryMethod = "SpecifiedPickupDirectory" 118 | $mail = New-Object System.Net.Mail.MailMessage 119 | 120 | $mail.From = $CreatorEmail 121 | $mail.To.Add("DLP@citrix.com") 122 | 123 | $mail.Subject = $FileID 124 | 125 | $mail.Attachments.Add($storagefile) 126 | 127 | # Populates message body with meaningful information about the file 128 | $mail.Body = "This was automatically generated.` 129 | 130 | File ID=$FileID ` 131 | File Name=$name ` 132 | Creation Date=$CreationDate ` 133 | Creator=$CreatorName ` 134 | Creator Email=$CreatorEmail ` 135 | Parent Folder=$ParentName ` 136 | File Size=$FileSizeinKB $unit ` 137 | Direct Link to Parent Folder=$link" 138 | 139 | 140 | $mail.IsBodyHtml = $true 141 | 142 | # Note that we might want to figure out how to give the .EML file a name of our choice 143 | $smtpClient.Send($mail) 144 | 145 | # Please note that if SFAntiVirus.exe is not run at this point in the script, then the AV / upload queue 146 | # will continue to grow, never get cleared out, and so re-running this script would create duplicate DLP incidents. 147 | # If you: 148 | # a) believe this script is configured and working properly (generating Symantec incidents for violations) 149 | # b) do not wish to scan uploaded files with an AV solution 150 | # c) wish to manually discard the current upload / AV queue items, 151 | # you could uncomment add this line (uncommented) at the end of the above for loop: 152 | # $Remove-SCQueueItem -qid $qid -id $qitem.id 153 | # However if AV is desired, then instead follow the instructions below: 154 | 155 | } 156 | # At this point, if all is configured correctly, all of the files in the 157 | # upload / AV queue have been processed and placed as email message files into the drop folder 158 | # so that Symantec DLP will have scanned them and created incidents if any violations 159 | # Else, if AV scanning is configured and desired 160 | # (see documentation on Anti-Virus scanning of StorageZones files 161 | # available here: http://support.citrix.com/proddocs/topic/sharefile-storagezones-31/sf-cfg-antivirus-scans.html) 162 | # then do NOT create a separate scheduled task for AV scanning--this script will serve as the one scheduled task. 163 | # --if you have the script at this point SFAntiVirus.exe tool. 164 | # This will cause the same items in the upload / AV queue to be processed, scanned, 165 | # and then discarded, ensuring no dupe incidents when this script is re-run 166 | # --to do that, uncomment the following lines: 167 | 168 | # cd c:\inetpub\wwwroot\Citrix\StorageCenter\Tools\SFAntiVirus 169 | # C:\inetpub\wwwroot\Citrix\StorageCenter\Tools\SFAntiVirus\SFAntiVirus.exe 170 | 171 | -------------------------------------------------------------------------------- /ShareFileSnapIn-Installer-x64/Product.wxs: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | = "2.0" AND POWERSHELL3VERSION >= "4.0")]]> 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 55 | 56 | 57 | 58 | 59 | 60 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /Test-ShareFileSnapIn/OrderedTests.orderedtest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ShareFileSnapIn/Parallel/ActionManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Management.Automation; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace ShareFile.Api.Powershell.Parallel 11 | { 12 | delegate void ProgressDoneDelegate(int index, long done); 13 | delegate void ProgressTotalDelegate(int index, long total); 14 | 15 | /// 16 | /// ActionManager class to start parallel copying operations 17 | /// 18 | class ActionManager 19 | { 20 | private Queue ActionsQueue; 21 | 22 | private ProgressDoneDelegate ProgressDone; 23 | private ProgressTotalDelegate ProgressTotal; 24 | 25 | private PSCmdlet CmdLetObj; 26 | private Dictionary ProgressInfoList; 27 | 28 | private object LockTransferred; 29 | private object LockTotal; 30 | 31 | private string folderName; 32 | 33 | /// 34 | /// Initialize 35 | /// 36 | public ActionManager(PSCmdlet cmdLetObj, string name) 37 | { 38 | this.ActionsQueue = new Queue(); 39 | 40 | this.ProgressDone = new ProgressDoneDelegate(UpdateCurrent); 41 | this.ProgressTotal = new ProgressTotalDelegate(UpdateTotal); 42 | this.LockTransferred = new object(); 43 | this.LockTotal = new object(); 44 | 45 | this.CmdLetObj = cmdLetObj; 46 | 47 | this.folderName = name; 48 | 49 | this.ProgressInfoList = new Dictionary(); 50 | } 51 | 52 | /// 53 | /// Add action to list 54 | /// 55 | /// Action type: UploadAction or DownloadAction 56 | internal void AddAction(IAction action) 57 | { 58 | this.ActionsQueue.Enqueue(action); 59 | } 60 | 61 | /// 62 | /// Execute all actions list in parallel (threads) 63 | /// 64 | internal void Execute() 65 | { 66 | int remainingCounter = ActionsQueue.Count; 67 | 68 | if (remainingCounter > 0) 69 | { 70 | int maxParallelThreads = System.Environment.ProcessorCount * 2; 71 | int runningThreads = 0; 72 | int threadIndex = 1; 73 | 74 | while (remainingCounter > 0) 75 | { 76 | // if actions queue is not empty and current running threads are less than the allowed max parallel threads count 77 | if (ActionsQueue.Count > 0 && runningThreads < maxParallelThreads) 78 | { 79 | Interlocked.Increment(ref runningThreads); 80 | IAction downloadAction = ActionsQueue.Dequeue(); 81 | Task t = Task.Factory.StartNew(async () => 82 | { 83 | for (int i=1; i <= 7; i++) 84 | { 85 | try 86 | { 87 | ProgressInfo fileProgressInfo = new ProgressInfo(); 88 | fileProgressInfo.ProgressTransferred = this.ProgressDone; 89 | fileProgressInfo.ProgressTotal = this.ProgressTotal; 90 | fileProgressInfo.FileIndex = threadIndex; 91 | 92 | ProgressInfoList.Add(threadIndex++, fileProgressInfo); 93 | if (i > 1) 94 | { 95 | // This means that this is a retry. In that case force the operation 96 | // Otherwise file already exists error is thrown 97 | downloadAction.OpActionType = ActionType.Force; 98 | downloadAction.CopyFileItem(fileProgressInfo); 99 | } 100 | else 101 | { 102 | downloadAction.CopyFileItem(fileProgressInfo); 103 | } 104 | // Task completed, break out of the loop. 105 | Log.Logger.Instance.Debug("Action on Filename : "+downloadAction.FileName+" got completed in "+i+" try"); 106 | break; 107 | } 108 | catch (AggregateException tce) 109 | { 110 | // This means ShareFile Client Api has cancelled the task. 111 | // Retry the operation. 112 | Log.Logger.Instance.Error(tce.Message + " Upload/Download action for " + downloadAction.FileName + "\n" + tce.StackTrace); 113 | 114 | if (i == 7) 115 | { 116 | // No need to wait 117 | break; 118 | } 119 | // Wait for sometime before retrying the operation 120 | double timeToWait = Math.Pow(2, i); 121 | await Task.Delay(TimeSpan.FromSeconds(timeToWait)); 122 | } 123 | catch (Exception e) 124 | { 125 | // This means operation failed due to some other reasons. 126 | // No need to retry, break out of the loop. 127 | Log.Logger.Instance.Error(e.Message + "\n" + e.StackTrace); 128 | break; 129 | } 130 | } 131 | Interlocked.Decrement(ref remainingCounter); 132 | Interlocked.Decrement(ref runningThreads); 133 | }); 134 | } 135 | 136 | UpdateProgress(); 137 | Thread.Sleep(1000); 138 | } 139 | 140 | 141 | UpdateProgress(); 142 | Thread.Sleep(1000); 143 | } 144 | } 145 | 146 | /// 147 | /// Get total number of actions 148 | /// 149 | public int TotalActions 150 | { 151 | get 152 | { 153 | return ActionsQueue.Count; 154 | } 155 | } 156 | 157 | private void UpdateCurrent(int index, long d) 158 | { 159 | lock (LockTransferred) 160 | { 161 | ProgressInfoList[index].Transferred = d; 162 | } 163 | } 164 | 165 | private void UpdateTotal(int index, long t) 166 | { 167 | lock (LockTotal) 168 | { 169 | ProgressInfoList[index].Total = t; 170 | } 171 | } 172 | 173 | private void UpdateProgress() 174 | { 175 | try 176 | { 177 | long total = 0, done = 0; 178 | int length = this.ProgressInfoList.Count; 179 | 180 | for (int i = 0; i < length; i++) 181 | { 182 | ProgressInfo p = this.ProgressInfoList.Values.ElementAt(i); 183 | total += p.Total; 184 | done += p.Transferred; 185 | } 186 | 187 | if (total == 0) 188 | { 189 | return; 190 | } 191 | 192 | int percentComplete = (int)(done * 100 / total); 193 | ProgressRecord progress = new ProgressRecord(1, 194 | string.Format("Copying '{0}'", this.folderName), 195 | string.Format("{0}% of {1}", percentComplete, GetSize(total))); 196 | 197 | progress.PercentComplete = percentComplete; 198 | //progress.CurrentOperation = "Downloading files"; 199 | //progress.StatusDescription = done + "/" + total; 200 | 201 | //progress.StatusDescription = string.Format("{0}% of {1}", percentComplete, GetSize(total)); 202 | 203 | this.CmdLetObj.WriteProgress(progress); 204 | } 205 | catch { } 206 | } 207 | 208 | private string GetSize(long total) 209 | { 210 | if (total > 1048576) 211 | { 212 | return string.Format("{0} MB", this.GetSizeRound(total, 1048576)); 213 | } 214 | else if (total > 1024) 215 | { 216 | return string.Format("{0} KB", this.GetSizeRound(total, 1024)); 217 | } 218 | else 219 | { 220 | return "1KB"; 221 | } 222 | } 223 | 224 | private string GetSizeRound(long total, long divider) 225 | { 226 | return Math.Round((double)total / divider, 2).ToString(); 227 | } 228 | } 229 | } 230 | --------------------------------------------------------------------------------