Сапиенские технологии

C# Windows 10 OpenFileDialog with long path

Marcell Hanyecz's user avatar

Setting FolderBrowserDialog.ShowNewFolderButton to true does not show the “New Folder” button

Offswitch's user avatar

Folder upload functionality in react/next app

Divyesh Bhuva's user avatar

SHBrowseForFolder: Move the selected entry into the visible area

perlfred's user avatar

Greetings. I am a beginner at c# and have run into a Special folder and string conversion issue [closed]

Brian Waldron's user avatar

Iterate through WINAPI TreeView

perlfred's user avatar

I used OpenFileDialog in Visual Studio “Windows Forms App(.NET Framework)” to open “Select Folder”, but the prompt doesn’t open. How can I solve this?

it's me's user avatar

What is the proper substitute for FolderBrowserDialog to use in a .net 6 WPF application? [duplicate]

Curtis's user avatar

Using Folder Browser in WPF .NET 6.0

John's user avatar

file browser and root opening at end of script

Lawrence's user avatar

Explorer “Browse for Folder”

G Beck's user avatar

How to select music folder on iOS in flutter

MarcoF's user avatar

Setting the ‘RootFolder’ property on a folderBrowserDialog prevents folder expansion

user3765883's user avatar

c# how to avoid repetition in foreach block

LFLJM's user avatar

alternative to FolderBrowserDialog in web forms

Sneha Mainkar's user avatar


The concept here is like getting your toolbox from the garage when you need to complete a task. Just as you have different collections of tools in your toolbox, ranging from general purpose to specialized, we do the same thing with our PowerShell modules.

Сапиенские технологии

In PowerShell, the toolboxes are generally modules. The commands in the modules are the tools. These commands should:

  • Have comment-based help so they will look and feel like all the other tools that are made available.
  • Take input on the command-line. What is needed should be made as clear as possible. This is mainly done through the use of the Help, meaningful names, and being strongly typed.
  • Be robust. As they are likely to be used in multiple contexts, possibly by multiple users, they must handle different inputs. The code should check that the input values work as expected; if not, either prompt for values (if that is appropriate) or return a meaningful error message identifying the problem.
  • Be a single output type. This can be returned as a value or by writing it to the pipeline. If you need to provide multiple pieces of information in the output, you should create a custom object—ideally as an instance of class—and have it contain all the information needed.
  • Be as flexible as possible and still be focused. In PowerShell, we should never, in my opinion, have a ‘Swiss army knife’ command.

The code below works perfectly except that each time you want to run it you have to edit the code to add the folder and path in from of $folder = “path”

$folder = "C:\0000"
$exec = "C:\Temp\Snap2HTML\Snap2HTML.exe"
Get-ChildItem -Path $folder -Directory | ForEach-Object { Start-Process -FilePath $exec -ArgumentList "-path:`"$($_.FullName)`" - outfile:`"$($_.FullName)`\$($_.Name)`.html`" -title:`"$($_.Name)`""

I am trying to add a windows select folder “pop-up” to the code below that would pass the selected folder to $folder = but my understanding of PS scripting is low.

I have tried the below but it does not work

Function Get-Folder($initialDirectory) { [void] [System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms') $FolderBrowserDialog = New-Object System.Windows.Forms.FolderBrowserDialog $FolderBrowserDialog.RootFolder = 'MyComputer' if ($initialDirectory) { $FolderBrowserDialog.SelectedPath = $initialDirectory } [void] $FolderBrowserDialog.ShowDialog() return $FolderBrowserDialog.SelectedPath
$folder = .SelectedPath
$exec = "C:\Temp\Snap2HTML\Snap2HTML.exe"
Get-ChildItem -Path $folder -Directory | ForEach-Object { Start-Process -FilePath $exec -ArgumentList "-path:`"$($_.FullName)`" - outfile:`"$($_.FullName)`\$($_.Name)`.html`" -title:`"$($_.Name)`""
}

I have been continuing to try different things and I have found the new code below that opens the windows folder dialog box which works (on my machine) on another website.

This code stores the folder location in PowerShell as <$browse.SelectedPath>

I have not provided a link to the site as I am unsure if I am supposed to.

function Find-Folders { [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null [System.Windows.Forms.Application]::EnableVisualStyles() $browse = New-Object System.Windows.Forms.FolderBrowserDialog $browse.SelectedPath = "C:\" $browse.ShowNewFolderButton = $false $browse.Description = "Select a directory" $loop = $true while($loop) { if ($browse.ShowDialog() -eq "OK") { $loop = $false #Insert your script here } else { $res = [System.Windows.Forms.MessageBox]::Show("You clicked Cancel. Would you like to try again or exit?", "Select a location", [System.Windows.Forms.MessageBoxButtons]::RetryCancel) if($res -eq "Cancel") { #Ends script return } } } $browse.SelectedPath $browse.Dispose()
} Find-Folders
$folder = .SelectedPath
$exec = "C:\Temp\Snap2HTML\Snap2HTML.exe"
Get-ChildItem -Path $folder -Directory | ForEach-Object { Start-Process -FilePath $exec -ArgumentList "-path:`"$($_.FullName)`" -outfile:`"$($_.FullName)`\$($_.Name)`.html`" -title:`"$($_.Name)`""
}
.SelectedPath : The term '.SelectedPath' is not recognized as the name of a cmdlet, function, script file, or operable
program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:33 char:11
+ $folder = .SelectedPath
+ ~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (.SelectedPath:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException

Petrut Belingher

Azure Storage — Flexible & Cheap

Another interesting issue I had at work recently was related to an Azure Storage Account. We had this solution that encompasses an Azure Function with a Blob Trigger to fetch a file from a Blob Container of an Azure Storage Account. This Azure Storage Account had to be somehow publicly reachable from the internet in order to ingest the files that would afterwards be processed by the Azure Function. This left us with an interesting decision to make. While you can expose a Storage Account publicly to the internet, and while you can access a Blob Container with a SAS Token, this might not be the most secure way to do so.

:/>  ✅ Как восстановить ярлыки программ на рабочем столе Windows 10 если они слетели -
SAS Access Flow on an Azure Storage Account

My solution was heavily inspired by another solution used in a different part of our project, where a Storage Account was configured as a Backend on an Application Gateway and Files were uploaded into it using the Blob API and Access Tokens. And this is what I ended up doing as well. The Storage Account is now not publicly exposed to the internet, but the Blob Container required for file ingest is.

This is how the configuration looks like on the Application Gateway. We first have the Ingest Backend Pool defined on the Application Gateway:

This Backend Pool will represent the Ingest Storage Account which has Public Access Disabled, but which has a Private Endpoint that is reachable from the Application Gateway’s Subnet on the Network Security Group Level.

This Backend will have a pretty basic rule attached to it that will link an HTTPS Listener to the Backend Pool configured with a set of Backend HTTPS Settings:

The HTTPS Settings are not all that special either, we simply configure HTTPS traffic to our Backend Pool and we let the Application Gateway automatically pick up a Host from the Backend Pool. Last but not least, we configure a Custom Probe on this Backend, the reason for this being explained later on:

The Listener is also configured to use only HTTPS traffic and it is configured with a specific Host Name that will be listened and with a Certificate:

Finally, we have the Health Probe:

The Health Probe is special because you will need to include the 400 HTTP response status code as a valid HTTP status code for Storage Account endpoints. Without this change being made, your Application Gateway will always return 502 — Bad Gateway even if all is fine connectivity-wise.

After we create a Frontend IP Configuration for the Application Gateway, the only thing remaining is to expose the Application Gateway on our DNS Zone and it’s off to the races. You can now access the Blob Container of that Storage Account.

What I showed above are all screenshots from the Azure Portal, but you can pretty much do this entire configuration in Terraform. This is also how it’s represented in our environment. Everything is in Terraform.

So now that we have our Application Gateway and Storage Accounts Configured, it all comes back to how we actually upload files here. This eventually all comes down to using the Blob Storage API.

The Blob Storage API can really be used from a variety of programming languages, but for a Proof of Concept purpose, I decided to use PowerShell to demonstrate this process end-to-end.

Using this token you can then generate a Payload message that you can send to your Application Gateway endpoint (which will now respond to Blob API Requests):

The Script above will scan an OS Path, it will check all the files in this Path, it will get the Azure AD Access Token, generate the Headers required for the Upload Request, open the File and Read it completely and then, using the Invoke-WebRequest cmdlet, it will try to upload the file. If any error occurs, then a very basic log message will be written into a log file.

Using this code snippet we have file upload into the Storage Account as well. So what still remains here? There is still the matter of the Access Permissions on the Storage Account. We are using a Service Principal, so access from the get-go is not very traceable. How do we make it more secure? Well, the answer is we build a Custom Azure Role for the Service Principals used to Upload the Files.

So now we have a script to upload the files into the Storage Account through the Application Gateway. Cool! How can we automate this? We can build a scheduled task to run this script automatically periodically. In the end, this is what I did as well using this Script:

I did try to make it a little bit prettier with a pop-up for the Folder that you want to upload your file from, but really you can customize this however you want and however it fits your solution.

And here is an example of how the fetching works:

Finally, what you can do to be complaint with the monitoring part of the solution, is to set some scheduled query alerts (through Terraform as well) — one that will monitor the amount of files ingested into the Storage Account, and one — if any file was not correctly processed by the blob trigger. Here are the KQL queries I used:

The above queries can help you monitor if you randomly get a big enough number of writes into your Blob Containers (which might be a sign of DDoS attacks, for example) and if any Files processed by the Azure Function’s Blob Trigger goes into the webjobs-poison queue. And that’s it!

:/>  Forensic Analysis of the Zone.Identifier Stream
Thank you for reading until the end!

So what did we learn from this article? Application Gateway is a brilliant, flexible, awesome solution! You can adapt it to your needs quite easily (as long as your needs are in the Layer 7 in the OSI Stack; at the time of writing Microsoft has Layer 4 support in Public Preview on Application Gateway). We also learned that, as long as you are a bit more relaxed from a security perspective, you can do whatever you want from PowerShell, which is awesome in itself, isn’t it?

Feedback

We love to hear from you! Please comment below, or in our feedback forum and reference this post.

A Case Study

As a Microsoft Certified Trainer, I download resources for delivering courses.  The materials are periodically updated, making it necessary to check if I have already downloaded the latest version.  While there are date stamps and comments about the changes on the download site, I frequently want to compare the new files (the lab files in particular) with the ones I have on my computer.  To do this, I need to compare the files from two folders (the folder I am currently using and the one with the latest downloads) so I can see what, if anything, has changed.

Requirements

I require two tools for the comparison:

  • A browser to select the folders that I want to compare.
  • A tool to compare two files to see if they are the same.

The controller script will use the file browser class from the .NET Framework to identify the reference folder (the one I am currently using) and the comparison folder (the latest download) if I have not provided the paths on the command-line. This approach allows me to avoid having to hard code or type long paths when I run the utility.

It will then go through each file in the reference folder, find the file with the matching name in the comparison folder, and then call the comparison function to check if they are the same.

It will also provide a list of file names present in one folder but not the other.

In this first instance, I simply output the results of the comparison to the screen as I do not need to display the differences between the files where they exist.

The Solution

The code for the two tools:

<#
.SYNOPSIS Compare-File takes two file references and will test to see if the file contents are identical.
.DESCRIPTION Compare-File initially checks that the two files are identical in length and then performs a byte comparison to see if the contents are identical.
.PARAMETER ReferenceFile	A System.IO.FileInfo reference to a file on which to base the comparison.
.PARAMETER ComparisonFile	A System.IO.FileInfo reference to a file to compare with the reference file.
.EXAMPLE	Compare-File -ReferenceFile (Get-Item "C:\Data\File1.txt”) -ComparisonFile (Get-Item "C:\Data\File2.txt”)
.OUTPUTS A Boolean value to indicate if the files are identical
.NOTES Confirm Impact: Low Supports Positional Binding
#>
function Compare-File
{ [CmdletBinding(ConfirmImpact='Low')] Param ( [System.IO.FileInfo]$ReferenceFile, [System.IO.FileInfo]$ComparisonFile ) Begin { if ((Test-Path $ReferenceFile.FullName) -and (Test-Path $ComparisonFile.FullName)) { [bool]$identical = $true [int]$offset = 0 [Int64]$bytesRead = 0 [Int64]$bytesToRead = 0 } else { Throw ("Unabe to find either {0} or{1}." -f $ReferenceFile.FullName,$ComparisonFile.FullName) } } Process { if ($ReferenceFile.Length -eq $ComparisonFile.Length) { $bytesToRead = $ReferenceFile.Length [System.IO.FileStream]$reference = $ReferenceFile.OpenRead() [System.IO.FileStream]$comparison = $ComparisonFile.OpenRead() [Byte[]]$refBuffer = New-Object Byte[] $bytesToRead [Byte[]]$compBuffer = New-Object Byte[] $bytesToRead While (($bytesToRead -gt 0) -and $identical) { $bytesRead = $reference.Read($refBuffer, $offset, $bytesToRead) $comparison.Read($compBuffer,$offset, $bytesToRead) | out-null if ( -Not [System.Linq.Enumerable]::SequenceEqual($refBuffer, $compBuffer)) { $identical = $false } if ($bytesRead -gt 0) { $offset += $bytesRead $bytesToRead -= $bytesRead } } $reference.Close() $comparison.Close() } else { $identical = $false } } End { return $identical }
}
<#
.SYNOPSIS Get-FolderPath is a utility that launches a FolderBrowserDialog to enable the user to browse and select a folder.
.DESCRIPTION Get-FolderPath uses the FolderBrowserDialog from the .NET Framework to launch an explorer dialog to enable to user to select a folder.
.PARAMETER BrowserTitle	Default Value: "Select Folder"	A string to provide a prompt to the user regarding the type of folder being sought.
.EXAMPLE	Get-FolderPath -BrowserTitle "Select the folder for the log files."
.OUTPUTS Either a null if the dialog is cancelled or a string representing the selected folder path.
.NOTES Confirm Impact: Low Supports Positional Binding
#>
function Get-FolderPath
{ [CmdletBinding(ConfirmImpact='Low')] Param ( [String]$BrowserTitle = "Select Folder" ) Begin { [System.Windows.Forms.FolderBrowserDialog]$ofbd = New-Object System.Windows.Forms.FolderBrowserDialog $ofbd.Description = $BrowserTitle } Process { [String]$folderPath = $null if ($ofbd.ShowDialog() -eq "OK") { $folderPath = $ofbd.SelectedPath } return $folderPath }
} 

The actual work is carried out by:

function Compare-Folder
{ [CmdletBinding(ConfirmImpact='Low')] Param ( [String]$ReferenceFolderPath = (Get-FolderPath -BrowserTitle "Select Reference Folder"), [String]$ComparisonFolderPath = (Get-FolderPath -BrowserTitle "Select Comparison Folder") ) Begin { if ((Test-Path $ReferenceFolderPath) -and (Test-Path $ComparisonFolderPath)) { $referenceFiles = Get-ChildItem $ReferenceFolderPath -File $comparisonFiles = Get-ChildItem $ComparisonFolderPath -File $refFileNames = $referenceFiles | Select-Object -ExpandProperty Name $compFileNames = $comparisonFiles | Select-Object -ExpandProperty Name } else { Throw "There was a problem with the folder paths" } } Process { Write-Host ([String]::Format("Comparing files in folder {0}`nwith`nfiles in Folder {1}`n",$ReferenceFolderPath,$ComparisonFolderPath)) Write-Host "`nFiles present in both folders" -BackgroundColor Cyan foreach ($refFile in $referenceFiles) { foreach ($compFile in $comparisonFiles) { if ($refFile.Name -eq $compFile.Name) { Write-Host ("Comparing File {0}" -f $refFile.Name) $result = Compare-File -ReferenceFile $refFile -ComparisonFile $compFile if ($result) { Write-Host "The files are the same" -BackgroundColor Green } else { Write-Host "The files are different." -BackgroundColor Yellow -ForegroundColor Black } } } } Write-Host "`nFiles in the Reference Folder but not in Comparison Folder" -BackgroundColor Cyan foreach ($refFileName in $refFileNames) { if ($refFileName -notin $compFileNames) { Write-Host $refFileName } } Write-Host "`nFiles in the Comparison Folder but not in Reference Folder" -BackgroundColor Cyan foreach ($compFileName in $compFileNames) { if ($compFileName -notin $refFileNames) { Write-Host $compFileName } } }
}
Clear-Host
Compare-Folder 

I often structure my control code as a function and then call it in the same script so, it is straightforward if I decide to move it to a module later.

Note: Both PowerShell Studio and PrimalScript include ScriptMerge, a stand-alone application that compares files and folders and allows you to apply differences to either of the two compared items.

Controllers

When I want to do some work around the home, I start by collecting the tools needed, then working out the steps required and planning how I will complete the task. The controller script works the same way. Hopefully, you will already have the tools/commands already included in a module ready to be called. If you need to write a command and it seems to be specific to the task at hand, it should still be written in the same way as you would write a tool. That way, it can be moved to a module if it seems likely that it can be used more broadly

:/>  Как отключить блокировку экрана на Виндовс 10: 5 способов снятия и настройка

Commands written in controllers are generally not visible to any other code.

The controller script may get all the information from the command-line and only run through the code when you run the script. This makes it look like the code for a tool. There are still differences, such as it:

  • Is focused on the task—the bigger picture.
  • Will be responsible for setting up the context for the work.
  • May ask for more information if there is anything missing.
  • Should check that the required resources are available, such as files and network connections.
  • May be a single run-through or several options may be available as steps. There may likely be a menu option or UI so that it can be run several times.
  • Should be documented either as comment-based help or comment blocks as a header so that when someone else (or you in 6 months) looks at the code, you can quickly understand what is going on.

Looking at the UI side of things, it may be implemented as a text menu or as a Windows application written in PowerShell, as shown in the examples below:

The screenshots above are from a utility I developed using PowerShell Studio, enabling me to work with photos. The controller element—the GUI—lets me select a folder containing photos, select the photo I want, and then exam the metadata (including Exif data).

There are several sets of tools at play here. PowerShell Studio has its own Toolbox containing components to design the GUI:

Сапиенские технологии
PowerShell Studio – Toolbox

The image above shows part of the PowerShell Studio Toolbox. The elements listed here expose classes from the .NET Framework and make them easier to work with. These classes can also be accessed directly from your code (see the case study below).

I build the GUI by dragging items from the Toolbox onto the design canvas, configuring them if necessary, and writing the code that the elements work with.

The other tool sets are the general commands that PowerShell provides to work with files, and a custom toolset I have written that includes a command to extract metadata from a file. This command wraps a command-line utility that extracts the Exif data. By creating a tool for this functionality rather than embedding it in the controller, I can easily utilize it in multiple control environments or as a standalone command to examine a single file.

Clear-Host
[String]$selection = ""
do
{ Clear-Host Write-Host "#############################" Write-Host "# Ledger Processing Utility #" Write-Host "#############################`n" Write-Host "D. Display The Full Ledger" Write-Host "S. Display The SMSF Ledger" Write-Host "C. Display The Consultancy Ledger" Write-Host "`n###############################################`n" Write-Host "R. Report on Ledger" Write-Host "N. Create New Ledger" Write-Host "M. MYOB Chart of Accounts" Write-Host "Q. Quit" Write-Host "`n###############################################`n" $selection = Read-Host "Enter Selection" if ($selection -ne "Q") { $selectedTransactions = $null switch($selection) { "D" {$selectedTransactions = (Get-TheLedger |
Out-GridView -Title "Full Ledger" -OutputMode Multiple)} "S" {$selectedTransactions = (Get-TheLedger -AccountHolder SMSF |
Out-GridView -Title "SMSF Ledger" -OutputMode Multiple)} "C" {$selectedTransactions = (Get-TheLedger -AccountHolder Consultancy |
Out-GridView -Title "Consultancy Ledger" -OutputMode Multiple)} ## Processing options "R" {Get-LedgerReport | Out-GridView -Title "Latest Transaction Report."} "N" {New-FullLedger -Verbose} "M" {Get-MYOBChartOfAccounts} default {Write-Host "Unable to recognise $selection"} } Read-Host "Press Enter to continue" }
}until ($selection -eq "Q") 
Сапиенские технологии

The more powerful, complex interface is the GUI (although a good IDE makes it moderately simple).

Reference

Other blog articles by guest blogger Brent Challis:

  • Where is the Documents Folder?
  • Sudo for PowerShell – or – I meant to open the shell with elevated priveleges!
  • A simple fix for problems with Windows Forms WebBrowser