openfiledialog control set and jobs with credentials

Ask questions about creating Graphical User Interfaces (GUI) in PowerShell and using WinForms controls.
Forum rules
Do not post any licensing information in this forum.

Any code longer than three lines should be added as code using the 'Select Code' dropdown menu or attached as a file.
User avatar
ITFTECH
Posts: 15
Joined: Mon Dec 08, 2014 10:30 am

openfiledialog control set and jobs with credentials

Post by ITFTECH » Fri Sep 28, 2018 10:39 am

Product, version and build: PowerShell Studio 2018 v5.5.154
32 or 64 bit version of product: 64
Operating system: Win10
32 or 64 bit OS: 64
running everything in STA mode

I have a GUI app that collects file and folder information from the user with folderbrowserdialogs and an openfiledialog control (brought in from the control sets in the PowerShell Studio toolbox.) After gathering criteria, it builds a small script around an Unprotect-RMSFile command, and attempts to run it as a job with cloud-enabled credentials.

The process works, the credentials work and the job does its job... BUT ONLY if a "TextBox - Browse for File" control set has been used to select a file first. Otherwise it returns an ambiguous error complaining about an invalid path while trying to start the session.

ERROR: [localhost] An error occurred while starting the background process. Error reported: The directory name is invalid.
ERROR: + CategoryInfo : OpenError: (localhost:String) [], PSRemotingTransportException
ERROR: + FullyQualifiedErrorId : -2147467259,PSSessionStateBroken

Even when the script block is built with no reference to the control or the file it may select, the job only starts when openfiledialog1.showdialog() has been run, a file selected, and the dialog closed again.

UNLESS... I leave off the credentials, in which case, the Unprotect-RMSFile command tells me I'm not authorized (which I'm not.)

MORE INFO: when I tried removing the openfiledialog control set and putting in a new one, no credentialed job will start. I seems that PARTICULAR first control was the lynch pin... the new file dialog control set still operates as normal, but now no credentialed jobs will start.

Wondering if there was some corruption or weirdness, I rebuilt the app from scratch in a new project. All the aforementioned results repeated.

so.. one more crazy experiment... new project, has 2 text boxes, button, two folder browser control sets, and a label. Put in the code , ran it..
Error reported: The directory name is invalid.
took off the credentials, the JOB RUNS, but of course, the RMS command fails on permissions.

dragged in a file dialog control set, ran the app, selected a file, hit button... BOOM! it works.

Uh.. help! Why is running a background job with credentials hinged on the presence, and state of, an openfiledialog control set????

In case someone asks:
--tried both regular Start-Job and PSS's Job-Tracker control set.
--tried in run mode from PSS, debug mode, and compiled as an EXE
--tried running as normal user and elevated (local admin)
--tried substituting admin credentials for Azure credentials in Start-Job command (still got directory error)
--tried dragging in a regular openfiledialog control and making my own button to open it (still got directory error)
-- --so I dragged a "TextBox - Browse for File" control set next to it... and it started working

User avatar
davidc
Posts: 5913
Joined: Thu Aug 18, 2011 4:56 am

Re: openfiledialog control set and jobs with credentials

Post by davidc » Fri Sep 28, 2018 11:00 am

[TOPIC MOVED TO POWERSHELL GUIS FORUM BY MODERATOR]
David
SAPIEN Technologies, Inc.

jvierra
Posts: 13939
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: openfiledialog control set and jobs with credentials

Post by jvierra » Fri Sep 28, 2018 11:17 am

Without a simple code example there is no way to know where you are making your mistakes.

User avatar
ITFTECH
Posts: 15
Joined: Mon Dec 08, 2014 10:30 am

Re: openfiledialog control set and jobs with credentials

Post by ITFTECH » Fri Sep 28, 2018 12:14 pm

Here's all that code that might run during my 'experiments'. The dialogs were all brought in with "Textbox - Browse for File" and "Textbox - Browse for Folder" control sets. Log-Session event is just a custom function that formats text for the log window on the form.
$txt... is a text box
btn, button
rad, radio button in a group
chk, checkbox

Code: Select all

$btnRMSFile_Click={
	if($openfiledialog2.ShowDialog() -eq 'OK')
	{
		$txtRMSFile.Text = $openfiledialog2.FileName
	}
}
$btnRMSFolder_Click={
	if($folderbrowserdialog1.ShowDialog() -eq 'OK')
	{
		$txtRMSFolder.Text = $folderbrowserdialog1.SelectedPath
	}
}
$btnFolderOut_Click={
	if($folderbrowserdialog2.ShowDialog() -eq 'OK')
	{
		$txtFolderOut.Text = $folderbrowserdialog2.SelectedPath
	}
}
$btnFileOut_Click={
	if($folderbrowserdialog4.ShowDialog() -eq 'OK')
	{
		$txtFileOut.Text = $folderbrowserdialog4.SelectedPath
	}
}
$btnFileList_Click={
	if($folderbrowserdialog3.ShowDialog() -eq 'OK')
	{
		$txtFileList.Text = $folderbrowserdialog3.SelectedPath
	}
}
$btnFileStatus_Click={
	if (Test-Path $txtRMSFile.Text)
	{
		$status = Get-RMSFileStatus -File $txtRMSFile.Text
		Log-SessionEvent -app -Message ("You checked a file for RMS protection...`r`nFile:" + $status.FileName + "`r`nStatus:" + $status.Status)
	}
	else { Log-SessionEvent -app -Message "ERROR: Couldn't find the file you're trying to check." }
}
$btnFileStatusList_Click={
	if (Test-Path $txtRMSFolder.Text)
	{
		$FileStatus = @()
		if ($chkRecurse.Checked) { $Targets = Get-ChildItem -PSPath $txtRMSFolder.Text -Recurse }
		else                     { $Targets = Get-ChildItem -PSPath $txtRMSFolder.Text }
		foreach ($file in ($Targets | Where-Object{ !$_.PSIsContainer }))
		{
			$FileStatus += Get-RMSFileStatus -File $file.PSPath
		}
		if ($chkStatusToGrid.Checked)
		{
			$FileStatus | Out-GridView -Title ("RMS protection status of files in " + $txtRMSFolder.Text)
		}
		if ($chkStatusToCSV.Checked)
		{
			if (Test-Path $txtFolderOut.Text)
			{
				$FileName = "\RMSStatus_" + (Get-Item -Path $txtRMSFolder).BaseName + ".csv"
				$FileStatus | Select-Object filename, Status | Export-Csv -Path $txtFolderOut.Text -NoTypeInformation
				Log-SessionEvent -app -Message ("Results written to $FileName")
			}else{Log-SessionEvent -app -Message ("ERROR: Couldn't find " + $txtRMSFolder.Text)}
		}
	}
	else { Log-SessionEvent -app -Message "ERROR: Couldn't find the folder you're trying to check." }
}
$btnUnprotectFile_Click={
	if ($txtRMSFile.Text -and (Test-Path $txtRMSFile.Text)){
		$usefile = $txtRMSFile.Text
		$usefileout = $txtFileOut.Text
		$scText = @"
		`$file='$usefile'
		`$folder='$usefileout'
		try{
			Unprotect-RMSFile -File `$file -OutputFolder `$folder -LogFile (`$folder + '\UnprotectFile.txt') -ErrorAction Stop}
		catch{
			`$Error[0]}
"@
		$go=$true
		if ($radFileInPlace.Checked)
		{
			$scText = $scText.Replace("-outputfolder `$folder","-InPlace")
			Log-SessionEvent -app -Message 'DEBUG: replaced outputfolder with InPlace'
		}
		if ($radFileToHere.Checked)
		{
			if (!(Test-Path $txtFileOut.Text))
			{
				Log-SessionEvent -app -Message "ERROR: Couldn't find the folder you've specified."
				$go=$false
			}
		}
		$scBlock = $ExecutionContext.InvokeCommand.NewScriptBlock($scText)
		if ($go -and $RMSCreds)
		{
			$lblStatus.Text = "Waiting for Bill Gate's approval"
			$timestamp = Get-Date -f hhmmss
			$result = Start-Job -Name "UnprotectFile$timestamp" -Credential $RMSCreds -InitializationScript { Import-Module AzureInformationProtection } -ScriptBlock $scBlock
			$job = Get-Job -Id $result.Id
			while ($job.State -ne "Completed" -and $job.State -ne "Failed")
			{
				Start-Sleep -Seconds 2
				$lblStatus.Text = $lblStatus.Text + "."
				$lblStatus.Refresh
				$job = Get-Job -Id $result.Id
			}
			$lblStatus.Text = ""
			Log-SessionEvent -app -Message ("JOB: " + $result.Name + " " + $result.State)
			$Received = Receive-Job -Id $result.Id
			Log-SessionEvent -app -Message ("RESULTS:`r`n-----------------------------------`r`nINPUT: " + $Received.InputFile + "`r`nDECRYPTED: " + $Received.DecryptedFile)
		}
	}
	else{Log-SessionEvent -app -Message "STOP: No file specified as target."}
}
$btnUnprotectAll_Click={
	if ($txtRMSFolder.Text -and (Test-Path $txtRMSFolder.Text))
	{
		$usefolder = $txtRMSFolder.Text
		$usefolderout = $txtFolderOut.Text
		if(!($usefolderout)){ $usefolderout = "c:\Temp"}
		$scText = @"
		`$folder='$usefolder'
		`$output='$usefolderout'
		try{
			Unprotect-RMSFile -Folder `$folder -OutputFolder `$output -LogFile (`$output + '\UnprotectFolder.txt') -ErrorAction Stop}
		catch{
			`$Error[0]}
"@
		if ($chkRecurse.Checked) { $scText = $scText.Replace("-erroraction stop", "-Recurse -erroraction stop") }
		$go=$true
		if ($radFolderInPlace.Checked)
		{
			$scText = $scText.Replace("-outputfolder `$output", "-InPlace")
			Log-SessionEvent -app -Message 'DEBUG: replaced outputfolder with InPlace'
		}
		if ($radFolderToHere.Checked)
		{
			if (!(Test-Path $txtFolderOut.Text))
			{
				Log-SessionEvent -app -Message "ERROR: Couldn't find the folder you've specified."
				$go=$false
			}
		}
		$scBlock = $ExecutionContext.InvokeCommand.NewScriptBlock($scText)
		if ($go -and $RMSCreds)
		{
			$lblStatus.Text = "Waiting for Bill Gate's approval"
			$timestamp = Get-Date -f hhmmss
			$result = Start-Job -Name "UnprotectFolder$timestamp" -Credential $RMSCreds -InitializationScript { Import-Module AzureInformationProtection } -ScriptBlock $scBlock
			$job = Get-Job -Id $result.Id
			while ($job.State -ne "Completed" -and $job.State -ne "Failed")
			{
				Start-Sleep -Seconds 2
				$lblStatus.Text = $lblStatus.Text + "."
				$lblStatus.Refresh
				$job = Get-Job -Id $result.Id
			}
			$lblStatus.Text = ""
			Log-SessionEvent -app -Message ("JOB: " + $result.Name + " " + $result.State)
			[array]$Received = Receive-Job -Id $result.Id
			Log-SessionEvent -app -Message ("FILES DECRYPTED: " + $Received.count)
		}
	}
	else{Log-SessionEvent -app -Message "STOP: No folder specified for targets."}
}
$buttonSetAzureCredentials_Click={
	$Global:RMSCreds = Get-Credential -Message "Enter credentials to use Azure module"
	$lblAzuretar.Text = $RMSCreds.UserName
	$lblAzuretar.Refresh
}


jvierra
Posts: 13939
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: openfiledialog control set and jobs with credentials

Post by jvierra » Fri Sep 28, 2018 1:09 pm

The following is not how to create a script block.

Code: Select all

		$scText = @"
		`$folder='$usefolder'
		`$output='$usefolderout'
		try{
			Unprotect-RMSFile -Folder `$folder -OutputFolder `$output -LogFile (`$output + '\UnprotectFolder.txt') -ErrorAction Stop}
		catch{
			`$Error[0]}
"@
It is like this:

Code: Select all

$folder = $txtRMSFolder.Text
$folderout = $txtFolderOut.Text

$scBlock = {
	try{
        Import-Module AzureInformationProtection
		Unprotect-RMSFile -Folder $using:folder -OutputFolder $using:folderout -LogFile ($using:folderout + '\UnprotectFolder.txt') -ErrorAction Stop
    }
	catch{
		$_
    }
}
$job = Start-Job -Name "UnprotectFolder$timestamp" -ScriptBlock $scBlock -Credential $RMSCreds 
I think if your fix all of those structures your issue will go away although there are a lot of other things that look very suspicious.

User avatar
ITFTECH
Posts: 15
Joined: Mon Dec 08, 2014 10:30 am

Re: openfiledialog control set and jobs with credentials

Post by ITFTECH » Fri Sep 28, 2018 2:04 pm

Yes, thank you. Sorry my POC code was a little rough. But please note the OP (original post)... it worked.

How's this?
  1. $jobscript = {
  2.  
  3.     param ($casenumber,$inputfolder,$outputfolder,$logfolder,$inplace,$recurse)
  4.  
  5.     $arguments = @{
  6.  
  7.         Folder      = $inputfolder;
  8.  
  9.         LogFile     = ($logfolder + "\$casenumber-UnprotectFolder.txt");
  10.  
  11.         ErrorAction = "Stop"
  12.  
  13.     }
  14.  
  15.     if ($inplace) { $arguments.Add("InPlace", $true) }
  16.  
  17.     else { $arguments.Add("OutputFolder", $outputfolder) }
  18.  
  19.     if ($recurse) { $arguments.Add("Recurse", $true) }
  20.  
  21.    
  22.  
  23.     try { Unprotect-RMSFile @arguments }
  24.  
  25.     catch { $Error[0] }
  26.  
  27. }
  28.  
  29. $update = {
  30.  
  31.     param ($job)
  32.  
  33.     $lblStatus.Text = $lblStatus.Text + "."
  34.  
  35.     $lblStatus.Refresh
  36.  
  37. }
  38.  
  39. $complete = {
  40.  
  41.     param ($job)
  42.  
  43.     [array]$results = Receive-Job -Job $job
  44.  
  45.     Log-SessionEvent -app -Message ("result count: " + $results.Count)
  46.  
  47.     Log-SessionEvent -app -Message ($results -join "`r`n")
  48.  
  49. }
  50.  
  51.  
  52.  
  53. $button1_Click={
  54.  
  55.     $JobID = Add-JobTracker `
  56.  
  57.                 -Name "$casenumber-UnprotectFolder" `
  58.  
  59.                 -JobScript $jobscript `
  60.  
  61.                 -CompletedScript $complete `
  62.  
  63.                 -UpdateScript $update `
  64.  
  65.                 -ArgumentList ($txtCaseNumber.Text, $textbox1.Text, $textbox2.Text, $textbox2.Text, $false, $false) `
  66.  
  67.                 -PSCred $RMSCreds
  68.  
  69. }
where the Add-JobTracker function was modified as:
  1.     Param(
  2.  
  3.     [ValidateNotNull()]
  4.  
  5.     [Parameter(Mandatory=$true)]
  6.  
  7.     [string]$Name,
  8.  
  9.     [ValidateNotNull()]
  10.  
  11.     [Parameter(Mandatory=$true)]
  12.  
  13.     [ScriptBlock]$JobScript,
  14.  
  15.     $ArgumentList = $null,
  16.  
  17.     [ScriptBlock]$CompletedScript,
  18.  
  19.         [ScriptBlock]$UpdateScript,
  20.  
  21.     [PSCredential]$PSCred)
  22.  
  23.    
  24.  
  25.     #Start the Job
  26.  
  27.     if ($PSCred) { $job = Start-Job -Name $Name -Credential $PSCred -ScriptBlock $JobScript -ArgumentList $ArgumentList }
  28.  
  29.     else             { $job = Start-Job -Name $Name                                -ScriptBlock $JobScript -ArgumentList $ArgumentList }
That's the code from the latest iteration. My point, in the OP, is that I've tried this six ways from Sunday. Four different projects, built every way I know. No matter what method I use, or what code surrounds it...

Start-Job -Name 'Name' -Credential $PSCredential -ScriptBlock $scriptblock

runs fine in the form app, BUT ONLY with a "Textbox - Browse for File" control set on the form that's been opened and assigned before attempting the session.

Start-Job -Name 'Name' -ScriptBlock $scriptblock

always runs fine, but then doesn't have the permissions it needs.

I don't believe it's the code. There's something about that control set that brings something to the project, or the main form, or some other configuration, that I'm missing (because when I build the pair myself, it doesn't work.) All versions of my code (from the sloppiest POC, to the neatest, newest drag-n-drop templates included with PSS, have worked... perfectly... when the control set is there, and never when it's not. If I delete the control set and put in another, identical set, the form app never runs a credentialed background job again. I have to create a new one.

This is the help I require:
- What does the inclusion (and use) of that control set do to the project/form/configuration that I should be adding by design?
- Am I using the wrong kind of project? I start with a basic multiform, STA project. My only deviation from default is the directory and a Git ignore file.
- Are there .net or other updates required (or in best practice) for my version of PSS?

I realize this is complex and weird, but my coworkers and I have been at this for days. We need some guidance. I don't know what else to try. I'd reinstall the whole Sapien suite if I thought it'd help. Please let me know if there's any other configuration information or form settings that you want me to enumerate here.

Thank you so much for your time.
mdj

jvierra
Posts: 13939
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: openfiledialog control set and jobs with credentials

Post by jvierra » Fri Sep 28, 2018 2:21 pm

You are way overcomplicating this. There si no dependency.

Controls are independent of the form which is just a container.

The issue you are having is likely because you have uninitialized variables or missing objects. Without a complete working example we cannot be of any help.

You are using way too many variable rea-assignments which can lead to situations where variables are not set or are set wrong.

The best thing to do is to use the debugger and inspect the variables one line at a time.

The issue you are experiencing is because of something broken or incorrect in your code. It is not because of controls, forms or the project type. We cannot fix this for you as we cannot run your code. You really need to use the debugger or start over and build this one piece at time until you detect your mistake.

User avatar
ITFTECH
Posts: 15
Joined: Mon Dec 08, 2014 10:30 am

Re: openfiledialog control set and jobs with credentials

Post by ITFTECH » Fri Sep 28, 2018 3:12 pm

Possibly... but I have, in recent iterations, designed the simplest code necessary to take input from a form and submit the appropriate script to the job, and return results to the form. Do you see the latest code as 'way over complicated'? or the previous? because that's about all the code in the project. I initialize some globals like current user and get credentials at start up. There are 4 text boxes, and one button on the latest attempt.

"Way too many variable reassignments" was applicable to the first attempt(s), yes, but if you still see that in the latest code snippets, please point it out.

I have been in the debugger extensively. No variable is unassigned or badly assigned at the time of the failure. I've even checked all their types.

That being said, I will build this again from scratch, one element at a time, and let you know if/when I encounter errors.

If I attach a document, can you read a Word docx?

jvierra
Posts: 13939
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: openfiledialog control set and jobs with credentials

Post by jvierra » Fri Sep 28, 2018 3:23 pm

It is hard to understand what you are calling a failure. You ill need to get more explicit information about what is failing and why.

Why do you need a Word document? Yes I read Word.

User avatar
ITFTECH
Posts: 15
Joined: Mon Dec 08, 2014 10:30 am

Re: openfiledialog control set and jobs with credentials

Post by ITFTECH » Fri Sep 28, 2018 4:04 pm

Failure: (from OP)
ERROR: [localhost] An error occurred while starting the background process. Error reported: The directory name is invalid.
ERROR: + CategoryInfo : OpenError: (localhost:String) [], PSRemotingTransportException
ERROR: + FullyQualifiedErrorId : -2147467259,PSSessionStateBroken

This error can only be read when in run mode in the PSS environment. I don't know where else to capture it. It isn't returned by $_ in the catch in the script. The receive-job returns null. The job never actually starts, I'm assuming, because the script sent to it never runs.

I'm building the simplest form possible that can test:
1. start-job w/credentials input by user
2. run a command in that job that
a. receives arguments from the form
b. proves the credentials work
3. get result of that job, or error

If I can reproduce the problem, I will send as detailed a report as possible, with configurations, steps taken, code and screenshots. I usually bundle that all in a document and attach, but I can find a way to present it on this forum, if that's easier for you to digest on your side.

It's Friday afternoon and I have to leave work, so I'll need to continue this effort in the evening. Will this thread be monitored between now and Monday?

Locked