From 101f9737738285397f0d3883a16cda361b9ce1c4 Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Tue, 24 Mar 2026 11:18:11 -0500 Subject: [PATCH 01/24] Removed Borg template and updated LICENSE per SecDev advisement --- .borg.template.toml | 15 --------------- CHANGELOG.md | 4 ++++ LICENSE | 3 ++- 3 files changed, 6 insertions(+), 16 deletions(-) delete mode 100644 .borg.template.toml diff --git a/.borg.template.toml b/.borg.template.toml deleted file mode 100644 index 1b64822..0000000 --- a/.borg.template.toml +++ /dev/null @@ -1,15 +0,0 @@ -# This file configures `borg` when this repository is used as a source. -# This file should only be present in a template repository. - -# If this file is present in a child repository, it should be deleted. - -[template] -files = [ - ".github/workflows/pr_reminder.yml", - ".github/workflows/cleanup.yml", - "CODE_OF_CONDUCT.md", - "SECURITY.md", -] -[generate.gitattributes] -# Include all template files above -include_template_files = true diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bc22af..dfc2a91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [0.0.2] - 2026-03-24 + + - Updated license file and remove borg template + ## [0.0.1] - 2026-03-17 ### Added diff --git a/LICENSE b/LICENSE index d82e321..7e3f76f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ -Copyright (c) 2026 University of Illinois. All rights reserved. +Copyright (c) 2026 Richard Donovan and the Board of Trustees of the +University of Illinois Developed by: Cybersecurity Engineering From 8d3142d932ddf17edb24a6671a7b8d44582f7ef8 Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Tue, 24 Mar 2026 13:13:45 -0500 Subject: [PATCH 02/24] updated End of Life --- CHANGELOG.md | 2 +- LICENSE | 2 ++ README.md | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfc2a91..8a2d2d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.0.2] - 2026-03-24 - - Updated license file and remove borg template + - Updated license file, and remove borg template ## [0.0.1] - 2026-03-17 diff --git a/LICENSE b/LICENSE index 7e3f76f..6ad5bc5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,5 @@ +University of Illinois/NCSA Open Source License + Copyright (c) 2026 Richard Donovan and the Board of Trustees of the University of Illinois diff --git a/README.md b/README.md index 712552b..9297854 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,14 @@ New-BoxFolderWithCollaboration ` -Login user@company.com ` -Role editor +#End-of-Life and End-of-Support Dates + +As of the last update to this README, the expected End-of-Life and End-of-Support dates of this product are November 2026. + +End-of-Life was decided upon based on these dependencies and their End-of-Life dates: + +Powershell 7.4 (November 2026) + # How do I help? Contributions are welcome. You can help by: From 668a9eacb78b2c15b681b251e987ae41ea899f79 Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Tue, 24 Mar 2026 16:07:47 -0500 Subject: [PATCH 03/24] added publishtogallery workflow --- .github/workflows/PublishToGallery.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/workflows/PublishToGallery.ps1 diff --git a/.github/workflows/PublishToGallery.ps1 b/.github/workflows/PublishToGallery.ps1 new file mode 100644 index 0000000..fa3f8ad --- /dev/null +++ b/.github/workflows/PublishToGallery.ps1 @@ -0,0 +1,7 @@ +try{ + Set-PSRepository -Name 'PSGallery' -InstallationPolicy 'Trusted' + Publish-Module -Path '.\src\UofIBox' -Repository 'PSGallery' -NuGetApiKey $ENV:NuGetApiKey -Force +} +catch{ + throw $_ +} \ No newline at end of file From be6377add6c074a87cf88ed1960a39e7ec753ae1 Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Tue, 24 Mar 2026 16:08:18 -0500 Subject: [PATCH 04/24] end of file line --- .github/workflows/PublishToGallery.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/PublishToGallery.ps1 b/.github/workflows/PublishToGallery.ps1 index fa3f8ad..2daef85 100644 --- a/.github/workflows/PublishToGallery.ps1 +++ b/.github/workflows/PublishToGallery.ps1 @@ -4,4 +4,4 @@ try{ } catch{ throw $_ -} \ No newline at end of file +} From 1c70f1c9527ee74d60fc5bfd3b8d35765a35f68b Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Tue, 24 Mar 2026 16:12:20 -0500 Subject: [PATCH 05/24] updated psd1 --- src/UofIBox/UofIBox.psd1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/UofIBox/UofIBox.psd1 b/src/UofIBox/UofIBox.psd1 index ce4f63e..ca0f8e6 100644 --- a/src/UofIBox/UofIBox.psd1 +++ b/src/UofIBox/UofIBox.psd1 @@ -68,15 +68,16 @@ PowerShellVersion = '7.0' # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. FunctionsToExport = @( - 'Get-BoxFolderData,' + 'Get-BoxFolderData', 'Get-BoxFileData', 'Invoke-BoxRestCall', - 'New-BoxFolderCollaboration' + 'New-BoxCollaboration', + 'New-BoxFolder', 'New-BoxSession', 'Receive-BoxFile', 'Receive-BoxFolder', 'Remove-BoxFolder', - 'Remove-BoxFile' + 'Remove-BoxFile', 'Send-BoxFile' ) From 5373ec59b75d8092661c8f351d6e0330348609c1 Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Tue, 24 Mar 2026 16:21:52 -0500 Subject: [PATCH 06/24] psd1 fixes --- src/UofIBox/UofIBox.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UofIBox/UofIBox.psd1 b/src/UofIBox/UofIBox.psd1 index ca0f8e6..c82fc18 100644 --- a/src/UofIBox/UofIBox.psd1 +++ b/src/UofIBox/UofIBox.psd1 @@ -86,7 +86,7 @@ FunctionsToExport = @( CmdletsToExport = @() # Variables to export from this module -VariablesToExport = @() +VariablesToExport = '*' # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. AliasesToExport = @() From 46938967ad4be3d5f921a2d25132089e57f3bed6 Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Wed, 25 Mar 2026 09:32:21 -0500 Subject: [PATCH 07/24] Fixed heading in Readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9297854..e5a3255 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ New-BoxFolderWithCollaboration ` -Login user@company.com ` -Role editor -#End-of-Life and End-of-Support Dates +# End-of-Life and End-of-Support Dates As of the last update to this README, the expected End-of-Life and End-of-Support dates of this product are November 2026. From 7a3467980ce28734414ece530dcbc09cb3ae42d7 Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Wed, 25 Mar 2026 11:00:07 -0500 Subject: [PATCH 08/24] PublishToGallery Workflow --- .github/workflows/PublishToGallery.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/workflows/PublishToGallery.yaml diff --git a/.github/workflows/PublishToGallery.yaml b/.github/workflows/PublishToGallery.yaml new file mode 100644 index 0000000..d1dd318 --- /dev/null +++ b/.github/workflows/PublishToGallery.yaml @@ -0,0 +1,16 @@ +name: PublishToGallery + +on: + release: + types: [created] +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Run publish script + env: + NuGetApiKey: ${{ secrets.NuGetApiKey }} + run: .github\workflows\PublishToGallery.ps1 + shell: pwsh \ No newline at end of file From 264a5bf7ff0816f65726bc1b813ad6e29ced6bda Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Wed, 25 Mar 2026 11:02:05 -0500 Subject: [PATCH 09/24] end of line --- .github/workflows/PublishToGallery.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/PublishToGallery.yaml b/.github/workflows/PublishToGallery.yaml index d1dd318..b70c3a5 100644 --- a/.github/workflows/PublishToGallery.yaml +++ b/.github/workflows/PublishToGallery.yaml @@ -13,4 +13,4 @@ jobs: env: NuGetApiKey: ${{ secrets.NuGetApiKey }} run: .github\workflows\PublishToGallery.ps1 - shell: pwsh \ No newline at end of file + shell: pwsh From b5677f88aec266833d9d8ab53dd07e1749a7f83b Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Wed, 25 Mar 2026 11:09:58 -0500 Subject: [PATCH 10/24] updated checkout version --- .github/workflows/PublishToGallery.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/PublishToGallery.yaml b/.github/workflows/PublishToGallery.yaml index b70c3a5..f919a99 100644 --- a/.github/workflows/PublishToGallery.yaml +++ b/.github/workflows/PublishToGallery.yaml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - name: Run publish script env: NuGetApiKey: ${{ secrets.NuGetApiKey }} From bd395447016a5b353d193ace244f7cf5b0f0cc52 Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Wed, 25 Mar 2026 15:28:30 -0500 Subject: [PATCH 11/24] Fixed function language in README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e5a3255..8774057 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,9 @@ File downloads Key Functions Folder Management -New-BoxFolderWithCollaboration – Create folders and assign users/roles +New-BoxFolder - Creates folders + +New-BoxCollaboration - Adds collaborators to folders Get-BoxFolder – Retrieve folder metadata From 984238a53cccf266426ee6e921f6d3294248302c Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Wed, 25 Mar 2026 15:31:11 -0500 Subject: [PATCH 12/24] Changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a2d2d1..63ed2b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [0.0.3] - 2026-03-25 + + -README Fixes, updated functions list to reflect proper available functions + ## [0.0.2] - 2026-03-24 - Updated license file, and remove borg template From 4b96a559df8361f59d187bf2b1f18d5925b077fe Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Tue, 31 Mar 2026 15:53:59 -0500 Subject: [PATCH 13/24] Added 3 new functions for collaboration management --- CHANGELOG.md | 7 ++ src/UofIBox/UofIBox.psd1 | 5 +- .../functions/public/Get-BoxCollaboration.ps1 | 60 ++++++++++++++++ .../public/Remove-BoxCollaboration.ps1 | 51 ++++++++++++++ .../functions/public/Set-BoxCollaboration.ps1 | 68 +++++++++++++++++++ 5 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 src/UofIBox/functions/public/Get-BoxCollaboration.ps1 create mode 100644 src/UofIBox/functions/public/Remove-BoxCollaboration.ps1 create mode 100644 src/UofIBox/functions/public/Set-BoxCollaboration.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 63ed2b3..3579c69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [0.0.4] - 2026-03-31 + + - Added the following functions; Get-BoxCollaboration, Set-Box Collaboration, Remove-BoxCollaboration. + Get-BoxCollaboration: Returns information about a specific collaborator + Set-BoxCollaboration: Changes an existing role for a collaborator + Remove-BoxCollaboration: Removes an existing Collaborator + ## [0.0.3] - 2026-03-25 -README Fixes, updated functions list to reflect proper available functions diff --git a/src/UofIBox/UofIBox.psd1 b/src/UofIBox/UofIBox.psd1 index c82fc18..4fa0f1f 100644 --- a/src/UofIBox/UofIBox.psd1 +++ b/src/UofIBox/UofIBox.psd1 @@ -78,7 +78,10 @@ FunctionsToExport = @( 'Receive-BoxFolder', 'Remove-BoxFolder', 'Remove-BoxFile', - 'Send-BoxFile' + 'Send-BoxFile', + 'get-boxcollaboration', + 'set-boxcollaboration', + 'remove-boxcollaboration' ) diff --git a/src/UofIBox/functions/public/Get-BoxCollaboration.ps1 b/src/UofIBox/functions/public/Get-BoxCollaboration.ps1 new file mode 100644 index 0000000..f961dd3 --- /dev/null +++ b/src/UofIBox/functions/public/Get-BoxCollaboration.ps1 @@ -0,0 +1,60 @@ +<# +.SYNOPSIS +Retrieves collaborators for a Box folder. + +.DESCRIPTION +Gets all collaborators assigned to a folder, including their roles and status. +Supports pagination to return all collaborators. + +.PARAMETER FolderId +ID of the folder. + +.EXAMPLE +Get-BoxCollaboration -FolderId 123456 + +.EXAMPLE +Get-BoxCollaboration -FolderId 123456 | Select-Object login, role +#> + +function Get-BoxCollaboration { + + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string]$FolderId + ) + + $Limit = 100 + $Offset = 0 + $Results = @() + + do { + + $Call = @{ + RelativeURI = "folders/$FolderId/collaborations?limit=$Limit&offset=$Offset" + Method = "GET" + } + + $Response = Invoke-BoxRestCall @Call + + if ($Response.entries) { + $Results += $Response.entries + } + + $Offset += $Limit + + } while ($Response.entries.Count -eq $Limit) + + # Clean output + $Results | ForEach-Object { + [PSCustomObject]@{ + Id = $_.id + Login = $_.accessible_by.login + Name = $_.accessible_by.name + Role = $_.role + Status = $_.status + CreatedAt = $_.created_at + ModifiedAt = $_.modified_at + } + } +} \ No newline at end of file diff --git a/src/UofIBox/functions/public/Remove-BoxCollaboration.ps1 b/src/UofIBox/functions/public/Remove-BoxCollaboration.ps1 new file mode 100644 index 0000000..ed8f189 --- /dev/null +++ b/src/UofIBox/functions/public/Remove-BoxCollaboration.ps1 @@ -0,0 +1,51 @@ +<# +.SYNOPSIS +Removes a collaborator from a Box folder. + +.DESCRIPTION +Deletes a collaboration by Collaboration ID. Supports pipeline input +from Get-BoxCollaboration. + +.PARAMETER CollaborationId +ID of the collaboration to remove. + +.EXAMPLE +Remove-BoxCollaboration -FolderId 123456 -CollaborationId 123456 + +.EXAMPLE +Get-BoxCollaboration -FolderId 123456 | + Where-Object Role -eq "viewer" | + Remove-BoxCollaboration -WhatIf +#> + +function Remove-BoxCollaboration { + + [CmdletBinding(SupportsShouldProcess)] + param( + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName + )] + [Alias("Id")] + [string]$CollaborationId + ) + + process { + + if (-not $CollaborationId) { + throw "CollaborationId cannot be null or empty." + } + + $Target = "Collaboration ID: $CollaborationId" + + if ($PSCmdlet.ShouldProcess($Target, "Remove collaborator")) { + + $Call = @{ + RelativeURI = "collaborations/$CollaborationId" + Method = "DELETE" + } + + Invoke-BoxRestCall @Call + } + } +} \ No newline at end of file diff --git a/src/UofIBox/functions/public/Set-BoxCollaboration.ps1 b/src/UofIBox/functions/public/Set-BoxCollaboration.ps1 new file mode 100644 index 0000000..6cb795b --- /dev/null +++ b/src/UofIBox/functions/public/Set-BoxCollaboration.ps1 @@ -0,0 +1,68 @@ +<# +.SYNOPSIS +Updates a Box collaboration role. + +.DESCRIPTION +Modifies an existing collaboration, typically to change the user's role. + +.PARAMETER CollaborationId +ID of the collaboration. + +.PARAMETER Role +New role to assign. + +.EXAMPLE +Get-BoxCollaboration -FolderId 123456 | + Where-Object Login -eq "user@company.com" | + Set-BoxCollaboration -Role co-owner +#> + +function Set-BoxCollaboration { + + [CmdletBinding(SupportsShouldProcess)] + param( + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName + )] + [Alias("Id")] + [string]$CollaborationId, + + [Parameter(Mandatory)] + [ValidateSet( + "editor", + "viewer", + "previewer", + "uploader", + "previewer uploader", + "viewer uploader", + "co-owner", + "owner" + )] + [string]$Role + ) + + process { + + if (-not $CollaborationId) { + throw "CollaborationId cannot be null or empty." + } + + $Target = "Collaboration ID: $CollaborationId" + + if ($PSCmdlet.ShouldProcess($Target, "Update role to '$Role'")) { + + $Body = @{ + role = $Role + } + + $Call = @{ + RelativeURI = "collaborations/$CollaborationId" + Method = "PUT" + Body = $Body + } + + Invoke-BoxRestCall @Call + } + } +} \ No newline at end of file From 7f3af2a937bd6ae9a87e3b839aa552b09d86daae Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Tue, 31 Mar 2026 15:54:39 -0500 Subject: [PATCH 14/24] updated blank spacing --- src/UofIBox/functions/public/Get-BoxCollaboration.ps1 | 2 +- src/UofIBox/functions/public/Remove-BoxCollaboration.ps1 | 2 +- src/UofIBox/functions/public/Set-BoxCollaboration.ps1 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/UofIBox/functions/public/Get-BoxCollaboration.ps1 b/src/UofIBox/functions/public/Get-BoxCollaboration.ps1 index f961dd3..94d2c2e 100644 --- a/src/UofIBox/functions/public/Get-BoxCollaboration.ps1 +++ b/src/UofIBox/functions/public/Get-BoxCollaboration.ps1 @@ -57,4 +57,4 @@ function Get-BoxCollaboration { ModifiedAt = $_.modified_at } } -} \ No newline at end of file +} diff --git a/src/UofIBox/functions/public/Remove-BoxCollaboration.ps1 b/src/UofIBox/functions/public/Remove-BoxCollaboration.ps1 index ed8f189..601b781 100644 --- a/src/UofIBox/functions/public/Remove-BoxCollaboration.ps1 +++ b/src/UofIBox/functions/public/Remove-BoxCollaboration.ps1 @@ -48,4 +48,4 @@ function Remove-BoxCollaboration { Invoke-BoxRestCall @Call } } -} \ No newline at end of file +} diff --git a/src/UofIBox/functions/public/Set-BoxCollaboration.ps1 b/src/UofIBox/functions/public/Set-BoxCollaboration.ps1 index 6cb795b..43eb3cc 100644 --- a/src/UofIBox/functions/public/Set-BoxCollaboration.ps1 +++ b/src/UofIBox/functions/public/Set-BoxCollaboration.ps1 @@ -65,4 +65,4 @@ function Set-BoxCollaboration { Invoke-BoxRestCall @Call } } -} \ No newline at end of file +} From c71d175c5ddeca034106a36caac52fb2bf68e2a4 Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Wed, 1 Apr 2026 14:14:14 -0500 Subject: [PATCH 15/24] Update Module Version Number --- src/UofIBox/UofIBox.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UofIBox/UofIBox.psd1 b/src/UofIBox/UofIBox.psd1 index 4fa0f1f..06379ed 100644 --- a/src/UofIBox/UofIBox.psd1 +++ b/src/UofIBox/UofIBox.psd1 @@ -10,7 +10,7 @@ RootModule = 'UofIBox.psm1' # Version number of this module. -ModuleVersion = '1.0.0' +ModuleVersion = '1.0.1' # Supported PSEditions # CompatiblePSEditions = @() From f786367ca39a031e865257b79b0b9de8e94decd6 Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Wed, 1 Apr 2026 14:36:13 -0500 Subject: [PATCH 16/24] Casing fixes --- src/UofIBox/UofIBox.psd1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/UofIBox/UofIBox.psd1 b/src/UofIBox/UofIBox.psd1 index 06379ed..59a27eb 100644 --- a/src/UofIBox/UofIBox.psd1 +++ b/src/UofIBox/UofIBox.psd1 @@ -79,9 +79,9 @@ FunctionsToExport = @( 'Remove-BoxFolder', 'Remove-BoxFile', 'Send-BoxFile', - 'get-boxcollaboration', - 'set-boxcollaboration', - 'remove-boxcollaboration' + 'Get-BoxCollaboration', + 'Set-BoxCollaboration', + 'Remove-BoxCollaboration' ) From 084849c154906181aec63179888be8602da957fe Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Thu, 2 Apr 2026 16:21:03 -0500 Subject: [PATCH 17/24] Upgrades and fixes --- src/UofIBox/UofIBox.psm1 | 1 + src/UofIBox/dscresources/.gitkeep | 0 .../functions/public/Invoke-BoxRestCall.ps1 | 17 ++- src/UofIBox/functions/public/Send-BoxFile.ps1 | 105 ++++++++++++++---- src/UofIBox/settings.json | 4 + 5 files changed, 103 insertions(+), 24 deletions(-) delete mode 100644 src/UofIBox/dscresources/.gitkeep create mode 100644 src/UofIBox/settings.json diff --git a/src/UofIBox/UofIBox.psm1 b/src/UofIBox/UofIBox.psm1 index 29b9165..d52cd77 100644 --- a/src/UofIBox/UofIBox.psm1 +++ b/src/UofIBox/UofIBox.psm1 @@ -1,3 +1,4 @@ +$Script:Settings = Get-Content -Path "$PSScriptRoot\settings.json" | ConvertFrom-Json $Script:BoxSession = $NULL [int]$Script:APICallCount = 0 diff --git a/src/UofIBox/dscresources/.gitkeep b/src/UofIBox/dscresources/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/UofIBox/functions/public/Invoke-BoxRestCall.ps1 b/src/UofIBox/functions/public/Invoke-BoxRestCall.ps1 index 47cadec..a02cfa8 100644 --- a/src/UofIBox/functions/public/Invoke-BoxRestCall.ps1 +++ b/src/UofIBox/functions/public/Invoke-BoxRestCall.ps1 @@ -19,6 +19,9 @@ Hashtable body that will be converted to JSON. .PARAMETER Upload Switch indicating the upload API endpoint should be used. +.PARAMETER Form +placeholder + .EXAMPLE Invoke-BoxRestCall -RelativeURI "folders/123" -Method GET @@ -38,6 +41,8 @@ function Invoke-BoxRestCall { [hashtable]$Body, + [hashtable]$Form, + [switch]$Upload ) @@ -52,10 +57,12 @@ function Invoke-BoxRestCall { } if ($Upload) { - $BaseURI = "https://upload.box.com/api/2.0/" + $BaseURI = "$($Script:Settings.UploadBaseURI)" + $contentType = "multipart/form-data" } else { - $BaseURI = "https://api.box.com/2.0/" + $BaseURI = "$($Script:Settings.BaseURI)" + $contentType = "application/json" } } @@ -64,7 +71,7 @@ function Invoke-BoxRestCall { $IVRSplat = @{ Headers = @{ Authorization = "Bearer $($Script:BoxSession.AccessToken)" - "Content-Type" = "application/json" + "Content-Type" = $contentType } Method = $Method Uri = "$BaseURI$RelativeURI" @@ -74,6 +81,10 @@ function Invoke-BoxRestCall { $IVRSplat.Add("Body", ($Body | ConvertTo-Json -Depth 10)) } + if ($Form) { + $IVRSplat.Add("Form", $Form) + } + Write-Verbose "Calling Box API: $Method $RelativeURI" try { diff --git a/src/UofIBox/functions/public/Send-BoxFile.ps1 b/src/UofIBox/functions/public/Send-BoxFile.ps1 index 1342244..333a2f7 100644 --- a/src/UofIBox/functions/public/Send-BoxFile.ps1 +++ b/src/UofIBox/functions/public/Send-BoxFile.ps1 @@ -1,54 +1,117 @@ <# .SYNOPSIS -Uploads a file to Box. +Uploads a file to Box from a local path or from memory. .DESCRIPTION -Uploads a local file to a specified Box folder. +Uploads a file to a specified Box folder. You can upload a file directly from a local path +or from an in-memory byte array, which is useful for generating files on the fly +without writing to disk. .PARAMETER FilePath -Local path of the file to upload. +(Local path upload) The path of the file on the local filesystem to upload. +Required when uploading from a file. + +.PARAMETER FileBytes +(In-memory upload) The file content as a byte array. Required when uploading from memory. + +.PARAMETER FileName +(In-memory upload) The name to give the file in Box. Required when using FileBytes. .PARAMETER ParentFolderId -Box folder ID where the file will be uploaded. +The Box folder ID where the file should be uploaded. .EXAMPLE +# Upload a local file Send-BoxFile -FilePath "C:\Temp\report.pdf" -ParentFolderId "123456" + +.EXAMPLE +# Upload a CSV from memory +$csv = $data | ConvertTo-Csv -NoTypeInformation +$bytes = [System.Text.Encoding]::UTF8.GetBytes($csv -join "`n") +Send-BoxFile -FileBytes $bytes -FileName "report.csv" -ParentFolderId "123456" #> function Send-BoxFile { - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = "FromPath")] param( - [Parameter(Mandatory)] + # --- File Path Upload --- + [Parameter(Mandatory, ParameterSetName = "FromPath")] [string]$FilePath, + # --- In-Memory Upload --- + [Parameter(Mandatory, ParameterSetName = "FromMemory")] + [byte[]]$FileBytes, + + [Parameter(Mandatory, ParameterSetName = "FromMemory")] + [string]$FileName, + + # --- Shared --- [Parameter(Mandatory)] [string]$ParentFolderId ) - if ($null -eq $Script:BoxSession) { - throw "No Box session established. Run New-BoxSession first." + switch ($PSCmdlet.ParameterSetName) { + + "FromPath" { + if (-not (Test-Path -Path $FilePath -PathType Leaf)) { + throw "File not found at path: $FilePath" + } + + $FileBytes = [System.IO.File]::ReadAllBytes($FilePath) + $FileName = [System.IO.Path]::GetFileName($FilePath) + } + + "FromMemory" { + } } $Attributes = @{ - name = [System.IO.Path]::GetFileName($FilePath) + name = $FileName parent = @{ id = $ParentFolderId } } | ConvertTo-Json -Compress - $Headers = @{ - Authorization = "Bearer $($Script:BoxSession.AccessToken)" - } + # --- Build multipart form body --- + $boundary = [System.Guid]::NewGuid().ToString() + $LF = "`r`n" + + $memStream = New-Object System.IO.MemoryStream + $writer = New-Object System.IO.StreamWriter($memStream) + + # --- attributes part --- + $writer.Write("--$boundary$LF") + $writer.Write("Content-Disposition: form-data; name=`"attributes`"$LF") + $writer.Write("Content-Type: application/json$LF$LF") + $writer.Write($Attributes + $LF) - $Form = @{ - attributes = $Attributes - file = Get-Item $FilePath + # --- file part --- + $writer.Write("--$boundary$LF") + $writer.Write("Content-Disposition: form-data; name=`"file`"; filename=`"$FileName`"$LF") + $writer.Write("Content-Type: application/octet-stream$LF$LF") + $writer.Flush() + + # Write raw file bytes + $memStream.Write($FileBytes, 0, $FileBytes.Length) + + # --- closing boundary --- + $writer.Write("$LF--$boundary--$LF") + $writer.Flush() + + $bodyBytes = $memStream.ToArray() + $memStream.Close() + + # --- Invoke API --- + $IVRSplat = @{ + Uri = "$($Script:Settings.UploadBaseURI)files/content" + Method = "POST" + Headers = @{ + Authorization = "Bearer $($Script:BoxSession.AccessToken)" + "Content-Type" = "multipart/form-data; boundary=$boundary" + } + Body = $bodyBytes } - Invoke-RestMethod ` - -Method POST ` - -Uri "$($Script:Settings.UploadBaseURI)files/content" ` - -Headers $Headers ` - -Form $Form -} + Invoke-RestMethod @IVRSplat +} \ No newline at end of file diff --git a/src/UofIBox/settings.json b/src/UofIBox/settings.json new file mode 100644 index 0000000..cde4321 --- /dev/null +++ b/src/UofIBox/settings.json @@ -0,0 +1,4 @@ +{ + "BaseURI": ["https://api.box.com/2.0/"], + "UploadBaseURI": ["https://upload.box.com/api/2.0/"] +} \ No newline at end of file From 1cf1642032ea6841726217c5b6b843a76656989c Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Thu, 2 Apr 2026 16:22:46 -0500 Subject: [PATCH 18/24] description update --- src/UofIBox/functions/public/Invoke-BoxRestCall.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UofIBox/functions/public/Invoke-BoxRestCall.ps1 b/src/UofIBox/functions/public/Invoke-BoxRestCall.ps1 index a02cfa8..4318523 100644 --- a/src/UofIBox/functions/public/Invoke-BoxRestCall.ps1 +++ b/src/UofIBox/functions/public/Invoke-BoxRestCall.ps1 @@ -20,7 +20,7 @@ Hashtable body that will be converted to JSON. Switch indicating the upload API endpoint should be used. .PARAMETER Form -placeholder +Hashtable of form fields for multipart form data requests. .EXAMPLE Invoke-BoxRestCall -RelativeURI "folders/123" -Method GET From dc35beabeba5656ec541df3f580106e5fe35cf6f Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Thu, 2 Apr 2026 16:23:10 -0500 Subject: [PATCH 19/24] trailing space --- src/UofIBox/functions/public/Send-BoxFile.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UofIBox/functions/public/Send-BoxFile.ps1 b/src/UofIBox/functions/public/Send-BoxFile.ps1 index 333a2f7..504cd17 100644 --- a/src/UofIBox/functions/public/Send-BoxFile.ps1 +++ b/src/UofIBox/functions/public/Send-BoxFile.ps1 @@ -114,4 +114,4 @@ function Send-BoxFile { } Invoke-RestMethod @IVRSplat -} \ No newline at end of file +} From 1e3ba5d49b495bce4d4e80a0b3463424564cf555 Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Fri, 3 Apr 2026 14:04:34 -0500 Subject: [PATCH 20/24] Version Updated for release --- CHANGELOG.md | 5 +++++ src/UofIBox/UofIBox.psd1 | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3579c69..a578af0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [0.0.5] - 2026-04-03 + + - Updated Send-BoxFile Function to have the ability to send files from memory. + - Updated Invoke-BoxRestCall to support Form Settings + ## [0.0.4] - 2026-03-31 - Added the following functions; Get-BoxCollaboration, Set-Box Collaboration, Remove-BoxCollaboration. diff --git a/src/UofIBox/UofIBox.psd1 b/src/UofIBox/UofIBox.psd1 index 59a27eb..c0f02e4 100644 --- a/src/UofIBox/UofIBox.psd1 +++ b/src/UofIBox/UofIBox.psd1 @@ -10,7 +10,7 @@ RootModule = 'UofIBox.psm1' # Version number of this module. -ModuleVersion = '1.0.1' +ModuleVersion = '1.0.2' # Supported PSEditions # CompatiblePSEditions = @() From 4ece1ec2a1229321ffc11e7207e4dc833926b66b Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Fri, 3 Apr 2026 14:11:21 -0500 Subject: [PATCH 21/24] blank space trailing --- src/UofIBox/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UofIBox/settings.json b/src/UofIBox/settings.json index cde4321..1171bf2 100644 --- a/src/UofIBox/settings.json +++ b/src/UofIBox/settings.json @@ -1,4 +1,4 @@ { "BaseURI": ["https://api.box.com/2.0/"], "UploadBaseURI": ["https://upload.box.com/api/2.0/"] -} \ No newline at end of file +} From 6428231ea4a0437155203fde8617cccc0746fdfb Mon Sep 17 00:00:00 2001 From: rdonovan92 Date: Tue, 7 Apr 2026 10:25:55 -0500 Subject: [PATCH 22/24] Changelog fixes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a578af0..7013c14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.0.5] - 2026-04-03 +### Changed - Updated Send-BoxFile Function to have the ability to send files from memory. - Updated Invoke-BoxRestCall to support Form Settings From 7474524edd3e8aedf5d2b47bf17c2251ce202d33 Mon Sep 17 00:00:00 2001 From: rdonovan92 <122567829+rdonovan92@users.noreply.github.com> Date: Tue, 7 Apr 2026 10:26:34 -0500 Subject: [PATCH 23/24] Apply suggestions from code review Co-authored-by: mabaumgartner <42626826+mabaumgartner@users.noreply.github.com> --- src/UofIBox/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UofIBox/settings.json b/src/UofIBox/settings.json index cde4321..1171bf2 100644 --- a/src/UofIBox/settings.json +++ b/src/UofIBox/settings.json @@ -1,4 +1,4 @@ { "BaseURI": ["https://api.box.com/2.0/"], "UploadBaseURI": ["https://upload.box.com/api/2.0/"] -} \ No newline at end of file +} From 346e9f13b536410636cbb3bca56fd376784896e5 Mon Sep 17 00:00:00 2001 From: rdonovan92 <122567829+rdonovan92@users.noreply.github.com> Date: Tue, 7 Apr 2026 11:06:19 -0500 Subject: [PATCH 24/24] Update CHANGELOG.md Co-authored-by: mabaumgartner <42626826+mabaumgartner@users.noreply.github.com> --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a578af0..2abb0e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.0.5] - 2026-04-03 +### Changed + + - Updated Send-BoxFile Function to have the ability to send files from memory. - Updated Invoke-BoxRestCall to support Form Settings