Public/Invoke-VBWorkstationReport.ps1
|
# ============================================================ # FUNCTION : Invoke-VBWorkstationReport # MODULE : VB.WorkstationReport # VERSION : 1.5.0 # CHANGED : 16-04-2026 -- All parameters made mandatory, defaults removed. # OutputPath validated upfront -- warns and stops if missing. # OutputPath validated again before upload. # AUTHOR : Vibhu Bhatnagar # PURPOSE : Orchestrates workstation data collection and uploads reports to Nextcloud # ENCODING : UTF-8 with BOM # ============================================================ function Invoke-VBWorkstationReport { <# .SYNOPSIS Generates a full workstation report and uploads it to Nextcloud. .DESCRIPTION Invoke-VBWorkstationReport orchestrates seven data collection functions: - Get-VBNetworkInterface -> <COMPUTERNAME>_NI.csv - Get-VBOneDriveFolderBackupStatus -> <COMPUTERNAME>_ODFB.csv - Get-VBSyncCenterStatus -> <COMPUTERNAME>_CNC.csv - Get-VBUserFolderRedirections -> <COMPUTERNAME>_UFR.csv - Get-VBUserPrinterMappings -> <COMPUTERNAME>_UPM.csv - Get-VBUserProfile -> <COMPUTERNAME>_UP.csv - Get-VBUserShellFolders -> <COMPUTERNAME>_USF.csv All parameters are mandatory -- no defaults are set. OutputPath must exist before the function runs; if it does not exist the function warns and stops immediately. Before upload, OutputPath is validated again and upload is skipped with a warning if no CSVs are found. .PARAMETER Credential PSCredential for Nextcloud authentication. Mandatory. .PARAMETER NextcloudBaseUrl Base URL of the Nextcloud instance. Mandatory. Example: 'https://vault.dediserve.com' .PARAMETER NextcloudDestination Remote folder path on Nextcloud where reports will be uploaded. Mandatory. Example: 'Realtime-IT/Reports' .PARAMETER OutputPath Local folder path where CSV reports are written before upload. Mandatory. The folder must already exist -- this function will not create it. Example: 'C:\Realtime\Reports' .PARAMETER SkipUpload When specified, reports are generated and saved locally but not uploaded to Nextcloud. Useful for testing or when Nextcloud is unavailable. .EXAMPLE $cred = New-Object PSCredential('username', (ConvertTo-SecureString 'AppPassword' -AsPlainText -Force)) Invoke-VBWorkstationReport -Credential $cred ` -NextcloudBaseUrl 'https://vault.dediserve.com' ` -NextcloudDestination 'Realtime-IT/Reports' ` -OutputPath 'C:\Realtime\Reports' .EXAMPLE Invoke-VBWorkstationReport -Credential $cred ` -NextcloudBaseUrl 'https://vault.dediserve.com' ` -NextcloudDestination 'Realtime-IT/Reports' ` -OutputPath 'C:\Realtime\Reports' ` -SkipUpload Generates all seven reports locally without uploading to Nextcloud. .OUTPUTS PSCustomObject Returns a summary object with: - ComputerName : Machine the report was collected from - OutputPath : Local folder where CSVs were written - ReportsGenerated: Number of CSV files successfully created - UploadResults : Array of upload result objects (empty when -SkipUpload is used) - Errors : Semicolon-separated error messages (null on full success) - Duration : Total execution time - Status : 'Success', 'PartialFailure', or 'Failed' - CollectionTime : Timestamp of the run .NOTES Version : 1.5.0 Author : Vibhu Bhatnagar Category: Windows Workstation Administration Requirements: - PowerShell 5.1 or higher - Administrative privileges (for registry hive access) - OutputPath directory must exist before calling this function - Network access to Nextcloud (unless -SkipUpload is specified) - VB.WorkstationReport and VB.NextCloud modules must be installed Security note: Never store credentials in plain text inside scripts. Use Get-Credential interactively, or retrieve credentials from a secrets manager / encrypted credential store. #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory)] [PSCredential]$Credential, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$NextcloudBaseUrl, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$NextcloudDestination, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$OutputPath, [switch]$SkipUpload ) $startTime = Get-Date $collectionTime = $startTime.ToString('dd-MM-yyyy HH:mm:ss') $computerName = $env:COMPUTERNAME $csvFiles = [System.Collections.Generic.List[string]]::new() $errors = [System.Collections.Generic.List[string]]::new() # -- Pre-flight: OutputPath must exist ------------------------------------------ if (-not (Test-Path -Path $OutputPath -PathType Container)) { Write-Warning "Invoke-VBWorkstationReport: OutputPath '$OutputPath' does not exist. Create the folder first and re-run." return [PSCustomObject]@{ ComputerName = $computerName OutputPath = $OutputPath ReportsGenerated = 0 UploadResults = @() Errors = "OutputPath '$OutputPath' does not exist." Duration = '00:00.000' Status = 'Failed' CollectionTime = $collectionTime } } try { # Clear previous reports Write-Verbose "Clearing existing CSVs from: $OutputPath" Remove-Item -Path (Join-Path $OutputPath '*.csv') -Force -ErrorAction SilentlyContinue # -- Report 1: Network Interfaces --------------------------------------------- $csvPath = Join-Path $OutputPath "${computerName}_NI.csv" Write-Verbose "Collecting network interfaces..." try { Get-VBNetworkInterface | Export-Csv -Path $csvPath -NoTypeInformation -Force $csvFiles.Add($csvPath) Write-Verbose "Saved: $csvPath" } catch { $errors.Add("NI: $($_.Exception.Message)") Write-Warning "Network interface collection failed: $($_.Exception.Message)" } # -- Report 2: OneDrive Folder Backup Status ---------------------------------- $csvPath = Join-Path $OutputPath "${computerName}_ODFB.csv" Write-Verbose "Collecting OneDrive folder backup status..." try { Get-VBOneDriveFolderBackupStatus | Export-Csv -Path $csvPath -NoTypeInformation -Force $csvFiles.Add($csvPath) Write-Verbose "Saved: $csvPath" } catch { $errors.Add("ODFB: $($_.Exception.Message)") Write-Warning "OneDrive folder backup collection failed: $($_.Exception.Message)" } # -- Report 3: Sync Center Status --------------------------------------------- $csvPath = Join-Path $OutputPath "${computerName}_CNC.csv" Write-Verbose "Collecting Sync Center status..." try { Get-VBSyncCenterStatus | Export-Csv -Path $csvPath -NoTypeInformation -Force $csvFiles.Add($csvPath) Write-Verbose "Saved: $csvPath" } catch { $errors.Add("CNC: $($_.Exception.Message)") Write-Warning "Sync Center collection failed: $($_.Exception.Message)" } # -- Report 4: User Folder Redirections --------------------------------------- $csvPath = Join-Path $OutputPath "${computerName}_UFR.csv" Write-Verbose "Collecting folder redirections..." try { Get-VBUserFolderRedirections -TableOutput | Export-Csv -Path $csvPath -NoTypeInformation -Force $csvFiles.Add($csvPath) Write-Verbose "Saved: $csvPath" } catch { $errors.Add("UFR: $($_.Exception.Message)") Write-Warning "Folder redirection collection failed: $($_.Exception.Message)" } # -- Report 5: User Printer Mappings ------------------------------------------ $csvPath = Join-Path $OutputPath "${computerName}_UPM.csv" Write-Verbose "Collecting printer mappings..." try { Get-VBUserPrinterMappings -TableOutput | Export-Csv -Path $csvPath -NoTypeInformation -Force $csvFiles.Add($csvPath) Write-Verbose "Saved: $csvPath" } catch { $errors.Add("UPM: $($_.Exception.Message)") Write-Warning "Printer mapping collection failed: $($_.Exception.Message)" } # -- Report 6: User Profiles -------------------------------------------------- $csvPath = Join-Path $OutputPath "${computerName}_UP.csv" Write-Verbose "Collecting user profiles..." try { Get-VBUserProfile | Export-Csv -Path $csvPath -NoTypeInformation -Force $csvFiles.Add($csvPath) Write-Verbose "Saved: $csvPath" } catch { $errors.Add("UP: $($_.Exception.Message)") Write-Warning "User profile collection failed: $($_.Exception.Message)" } # -- Report 7: User Shell Folders --------------------------------------------- $csvPath = Join-Path $OutputPath "${computerName}_USF.csv" Write-Verbose "Collecting user shell folders..." try { Get-VBUserShellFolders | Export-Csv -Path $csvPath -NoTypeInformation -Force $csvFiles.Add($csvPath) Write-Verbose "Saved: $csvPath" } catch { $errors.Add("USF: $($_.Exception.Message)") Write-Warning "User shell folder collection failed: $($_.Exception.Message)" } # -- Upload ------------------------------------------------------------------- $uploadResults = @() if (-not $SkipUpload) { # Validate OutputPath still exists and has CSVs before attempting upload if (-not (Test-Path -Path $OutputPath -PathType Container)) { $msg = "Upload skipped: OutputPath '$OutputPath' no longer exists." $errors.Add($msg) Write-Warning $msg } elseif ($csvFiles.Count -eq 0) { $msg = "Upload skipped: no CSV files were generated in '$OutputPath'." $errors.Add($msg) Write-Warning $msg } else { Write-Verbose "Uploading $($csvFiles.Count) file(s) to $NextcloudBaseUrl/$NextcloudDestination" $uploadResults = $csvFiles | Set-VBNextcloudFile -BaseUrl $NextcloudBaseUrl ` -Credential $Credential -DestinationPath $NextcloudDestination -Overwrite $failedUploads = @($uploadResults | Where-Object { $_.Status -eq 'Failed' }) if ($failedUploads.Count -gt 0) { $failedUploads | ForEach-Object { $errors.Add("Upload failed for $($_.SourceFile): $($_.Error)") Write-Warning "Upload failed: $($_.SourceFile) -- $($_.Error)" } } } } else { Write-Verbose 'Upload skipped (-SkipUpload specified).' } $duration = (Get-Date) - $startTime $statusCode = if ($errors.Count -eq 0) { 'Success' } elseif ($csvFiles.Count -gt 0) { 'PartialFailure' } else { 'Failed' } [PSCustomObject]@{ ComputerName = $computerName OutputPath = $OutputPath ReportsGenerated = $csvFiles.Count UploadResults = $uploadResults Errors = if ($errors.Count) { $errors -join '; ' } else { $null } Duration = '{0:mm\:ss\.fff}' -f $duration Status = $statusCode CollectionTime = $collectionTime } } catch { Write-Error -Message "Invoke-VBWorkstationReport failed: $($_.Exception.Message)" [PSCustomObject]@{ ComputerName = $computerName OutputPath = $OutputPath ReportsGenerated = $csvFiles.Count UploadResults = @() Errors = $_.Exception.Message Duration = '{0:mm\:ss\.fff}' -f ((Get-Date) - $startTime) Status = 'Failed' CollectionTime = $collectionTime } } } |