flancy
flancy copied to clipboard
Can't run latest Flancy as Job anymore
Repro script:
Start-Job -Name 'Flancy' -ScriptBlock {
Import-Module -Name 'Flancy' -ErrorAction Stop
New-Flancy -WebSchema @{
Method = 'Get'
Path= '/'
Script = {'Hello, world!'}
}
}
Wait-Job -Name 'Flancy' | Receive-Job
Output:
PS > .\Flancy-AsJob.ps1
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
2 Flancy BackgroundJob Running True localhost ...
Exception calling ".ctor" with "1" argument(s): "Unable to resolve type: Nancy.ViewEngines.ViewEngineApplicationStartup"
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
+ PSComputerName : localhost
You cannot call a method on a null-valued expression.
At .\flancy\flancy.psm1:395 char:9
+ $flancy.start()
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
PowerShell version:
Name : Windows PowerShell ISE Host
Version : 5.0.10018.0
InstanceId : 03eac871-dcbd-4e6a-8c7c-b5c018dbcda8
UI : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture : ru-RU
CurrentUICulture : en-US
PrivateData : Microsoft.PowerShell.Host.ISE.ISEOptions
DebuggerEnabled : True
IsRunspacePushed : False
Runspace : System.Management.Automation.Runspaces.LocalRunspace
This doesn't happen with this version of Flancy.
I think this is the same as issue #32
@h0rnman Agree. Curious, that I have no issues while running Flancy in PS console/ISE, only as job.
Is your ISE environment importing a different build of the module perhaps? I am seeing the error in both ISE and console.
I've nailed it! It all comes down to the Flancy's Path
parameter. When Flancy is run in the interactive PowerShell session and Path
parameter is not specified, it will be set to the current PowerShell's directory. But if you run it as a job, $PWD
points to the current user's My Documents
folder (C:\Users\Administrator\Documents
in my case).
Here is the code in the Flancy.psm1
that sets it:
if (!$path) {
$path = ''
if ($MyInvocation.MyCommand.Path) {
$path = Split-Path $MyInvocation.MyCommand.Path
} else {
$path = $pwd -replace '^\S+::',''
}
}
And that's where weird things start to happen: Nancy tries to access folder C:\Users\Administrator\Documents\My Music
which doesn't exist!
System.UnauthorizedAccessException: Access to the path 'C:\Users\Administrator\Documents\My Music' is denied.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileSystemEnumerableIterator`1.AddSearchableDirsToStack(SearchData localSearchData)
at System.IO.FileSystemEnumerableIterator`1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.IO.Directory.InternalGetFileDirectoryNames(String path, String userPathOriginal, String searchPattern, Boolean includeFiles, Boolean includeDirs, SearchOption searchOption, Boolean checkHost)
at System.IO.Directory.InternalGetFiles(String path, String searchPattern, SearchOption searchOption)
at Nancy.ViewEngines.DefaultFileSystemReader.GetFilenames(String path, String extension)
at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
at System.Linq.Enumerable.<DistinctIterator>d__81`1.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Nancy.ViewEngines.DefaultFileSystemReader.GetViewsWithSupportedExtensions(String path, IEnumerable`1 supportedViewExtensions)
at Nancy.ViewEngines.FileSystemViewLocationProvider.GetViewsFromPath(String path, IEnumerable`1 supportedViewExtensions)
at Nancy.ViewEngines.DefaultViewLocator..ctor(IViewLocationProvider viewLocationProvider, IEnumerable`1 viewEngines)
at lambda_method(Closure , Object[] )
at Nancy.TinyIoc.TinyIoCContainer.ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, NamedParameterOverloads parameters, ResolveOptions options)
I'm also able to reproduce this in the PowerShell session (not job). It looks like Nancy is trying to traverse down the given path, because when I set Path
to the root of my drive (E:\
), exception is thrown about E:\$RECYCLE.BIN\S-1-5-18
.
To get this details I've modified Flancy.psm1
to catch and unwind inner exceptions when creating new Flancy object. This gives you the full list of the exceptions, instead of the outer one.
Before:
$flancy = new-object "flancy.flancy" -argumentlist $url
After:
try
{
$flancy = new-object "flancy.flancy" -argumentlist $url
}
catch
{
function Unwind-Exception
{
Param($Exception)
if($Exception.InnerException)
{
$Exception.InnerException.PsObject.Properties | Select-Object -Property Name, Value
Unwind-Exception $Exception.InnerException
}
}
Unwind-Exception $_.Exception.InnerException
}
I will include the exception unwinding in flancy.psm1 in the devel branch. Doing that now. If you set your directory to something else in the job, is it working? I'd like to understand how to make it work. I'd also like to understand what's causing it.
never mind - I duplicated and was able to get it to work with this:
Start-Job -InitializationScript {import-module c:\flancy\flancy.psd1} -ScriptBlock {cd c:\flancy; new-flancy;while ($true) {sleep 60}}
I'm thinking the best way to fix this would be to create an asjob parameter. I could then do the following:
- load the module in the initialization script from get-module -listavailable flancy |select -expandproperty modulebase
- Set the current directory in the job to the current directory
- Pass any arguments as a single argument to the scriptblock
- Pass the arguments to the scriptblock to new-flancy
- Create the loop with a 60 minute sleep
Confirmed, this appears to be a bug in Nancy, not flancy. You cannot seem to set the root path to c:\users\username\documents. I attempted to compile it with that root path and it errors. Actually, I found that any directory (such as root drives due to the recycle bin) where a subfolder gives access denied appears to error. i'm unsure whether or not I can use the following to validate the rootdir just now.
Get-ChildItem c:\users\tome\documents -Depth 1 -force -Recurse -ea stop
It will work for my docs and for c-drive, but I'm unsure if the depth goes further in Nancy. For now, I wiil try adding the validation of the path with the above and catch the error to notify people that they cannot use that directory and to use the -path parameter to override the path.
I opened this in Nancy's issue list: https://github.com/NancyFx/Nancy/issues/2146
OK - We should be able to close this pending validation that @beatcracker can implement a workaround with -Path and that he now receives a better error message when not using -Path in a job (or changing directory in the job itself prior to calling new-flancy). Once confirmed, we'll close this, and then we'll implement asjob per Issue #25
I'm able to run Flancy as job if I specify path without inaccessible directories and I receive a new error message if path contains such inaccessible directories.
But we have to do something about the validation code, because it's very slow - it tries to enumerate all directories/subdirectories in given path. In my case it takes 3 seconds to start Flancy as job when Path
targets an empty directory and 25 seconds when Path
is set to the drive root (+ heavy HDD activity).
Well, we could opt for an easier way - I think it might be better anyway: Let's ensure that we are not in the root of a drive or that we are not in $env:userprofile\documents or $enf:userprofile\my documents. As long as path doesn't match those 3, chances are the person is in an ok directory. AND if they are not, they will get the normal access denied errors thanks to your update. Plus, we now have this documented in the parameter and we can update the examples and readme.md to call it out.
I think that's fair.
Yes, I was thinking along those lines. In fact, I don't even think that we should block user from supplying those paths, just check and Write-Warning
if they match.
Just figured out why accessing My Music
generates exception in Nancy (of course, it's a permissions issue, but a curious one): https://github.com/NancyFx/Nancy/issues/2146#issuecomment-162368570