Migrate class registration away from Butterfly

We currently rely on the controller.js file to register both front-end and back-end components.
For instance, OpenRefine operations are registered in controller.js with:
https://github.com/OpenRefine/OpenRefine/blob/606ad716f1bf91e24f04b31e79a18fc2fc42c1e2/main/webapp/modules/core/MOD-INF/controller.js#L157-L166
Beyond the fact that the use of a .js file to register things in the backend is quite confusing, I would like to migrate away from doing this registration there. The reason for this are that:

I would like to make it possible to use backend components (operations, facets, GREL functions…) outside of the context of a web app. Currently, those classes are exposed in the org.openrefine:main Maven artifact, but because the registration is done via this Java-interpreted Javascript file in Butterfly, third-party users of this Maven artifact need to re-declare all those components with their string identifiers. One can do this by copying the contents of this controller.js file, translating them to Java and including this in the third-party Java code (like I did in refine-memory-benchmark) but this is obviously not ideal since this duplicates code.
Moving away from this registration method would be a small step towards reducing our dependency on Butterfly. A generic (Java-based) way of registering those components would still be usable with any other web framework, so it would be one less thing to migrate should we leave Butterfly.

Proposed solution
We could use the Java Service Provider Interface (SPI) mechanism to let the core and extensions register such Java classes. It is not clear to me what SPI structure we should adopt though. Because SPI classes need to have a no-args constructor, the operation classes cannot be SPI classes themselves, but would need to be registered via a provider.
Java classes which are specific to Butterfly (such as Commands) could be kept with the existing registration mechanism.
Because this is a change in the extension interface, I would do this in change version 4 only, and keep version 3 as is.
Alternatives considered
There are alternatives to SPI which could also be considered

I'd say let's move completely off of Butterfly now.  Could we leverage Spring Boot here? Just one example that was given to me:
https://github.com/jonashackt/spring-boot-vuejs
Thymeleaf can use /srv/main/resources/static.  Additionally usage of frontend-maven-plugin might also be helpful?

As far as I know Spring is not an alternative to Butterfly in itself because I do not think it comes with an extension mechanism comparable to what Butterfly provides (an extension must be able to register new components both in the front-end and back-end). It is likely that one could build something similar on top of Spring, but this needs to be built in the first place. See the discussion on the forum about that: https://forum.openrefine.org/t/improving-the-ux-of-extension-install-and-butterfly/52
Let's keep the discussion about migrating out of Butterfly there, and use this issue for this much narrower proposal.

For sure I would not want to migrate the front-end components to be registered via SPI in Java. It would be a pretty bad experience.
My proposal is to only do this for back-end components. So the fact that a pure frontend extension does not need any Java files would remain true.

It was just an example, another thing would be that it's nice to have all "extension registration" in one place. Today, one can open controller.js and directly get a full overview of what an extension implements no matter if it's frontend or backend.
I'm a little bit skeptical against approaching this by just doing it for backend components rather than approaching the whole developer experience at once.

One other way to address the problem I have and still have a central place to register all components of an extension (be they in the back- or front-end) would be to migrate away from relying on an interpreted javascript file to a declarative format.
Concretely, this means that instead of a controller.js file, we would have a controller.json / controller.yaml / controller.toml file or something similar, which would basically store the same contents, structured differently.
This would have the following advantages:

fix the confusion created by the fact that although controller.js is a Javascript file, it is actually run by the backend.
make it possible to read this config file without executing arbitrary code in it, so potentially providing much better error messages when an extension is registering something it should not, or if it is incompatible with the current OpenRefine version
stop relying on a Javascript execution engine, Rhino, whose jar weighs 1.4MB

The main module defines some HTTP endpoints directly as javascript functions written in the controller.js: we would need to convert that to Java code in the process. I think that would be a good move independently. It feels wrong (and might have a performance impact) to have requests partly handled by a bit of Javascript code interpreted in Java.
To do this move I would make a new version of Butterfly which would use this new registration mechanism.
@Abbe98 what do you think?

@wetneb I like that approach very much, and it would open up for including metadata in such a config file which could be used for things like #5546, and even dependency management.

And 👍 for controller.toml !


[Need maintainer/owner]

We have recently moved on to a different containerized infrastructure using convox and are no longer maintaining this gem.  This gem is a simple rake/config wrapper around eb_deployer, so there aren't too many moving parts.
If you are interested in maintaining or taking over this project, please let me know, I'd like to see it continue - this solves some real pain when using EB.

I'd be happy to lend a hand - I love the gem and we use it extensively for our CD process.

I've added you @Tongboy

@rosskevin, @Tongboy We use this gem to deploy several apps. I haven't looked at the code of this gem yet, but I am happy to help!

@avinasha I cannot see much history in your github profile, so let's start with you submitting a few PRs first.  Thanks for your interest in helping.

@avinasha I have experience of using Elastic Beanstalk to deploy my Rails application. I would love to join as a maintainer.

@fbukevin likewise most of your profile is private repositories so I cannot see any history.  Please feel free to submit PRs and if those are good I'll add you.

@fbukevin I got your gitter message, I'll add you now.


Fix issue #753, iOS9 UIWebView probrem

Fix the broblem that #cboxOverlay is displayed over #colorbox
when page is scrolled down in UIWebView on iOS9.
To avoid UIWebView's probrem, add translate3d(0,0,0) to related element.

Thanks


tag the release

👋 thanks for the project, can you maybe tag the release? It would help distribute the project. :) Thanks!

Hi 👋 Thanks for your interest!
Yes, you can already install tfocus via cargo install tfocus, but you're right - having release tags on GitHub would be helpful. I'll update and create a release tag shortly. 😊

I'll set up automated releases using cargo-release soon. 😊
https://github.com/crate-ci/cargo-release


Last minute fixes

https://github.com/The-Poolz/Poolz-Back/issues/38
https://github.com/The-Poolz/Poolz-Back/issues/74
https://github.com/The-Poolz/Poolz-Back/issues/75
https://github.com/The-Poolz/Poolz-Back/issues/79

Plus the no-contract investment (or contractor but same sender?)

Plus the no-contract investment (or contractor but same sender?)


Guidance on Instrument Formatting

Come up with a set of standards on how platforms, instruments, tags, variable names, and other strings should be formatted within pysat. After coming up with guidelines, write them down, nicely, for everyone to see.

Pinging after discussion on telecon.  There should be a tutorial on adding an instrument as well.

Added more discussion to https://github.com/rstoneback/pysat/blob/doc_instrum_format/docs/new_instrument.rst to adress this issue.  Comments welcome.

Closed with merge of #226.


Added GN build file.

/cc @zanderso

This lgtm, but IIRC the intl package source of truth is somewhere else, and @alan-knight might need to land this change for us there.

Is this package different from say func in that respect?

I don't particularly know about func, but yes, it looks different. Note that all commits say "Created by MOE"

Found another way.


Update methods in README.md with asset elements

Motivation
Fixes #144.
Contains updates to readme with the new asset taxonomies functionality examples. I also fixed all the asset code samples to be up to date.
Checklist

[ ] Code follows coding conventions held in this repo
[ ] Automated tests have been added
[ ] Tests are passing
[ ] Docs have been updated (if applicable)
[ ] Temporary settings (e.g. variables used during development and testing) have been reverted to defaults

How to test
No need to test

Shouldn't this PR be pointed at vNext branch?

Shouldn't this PR be pointed at vNext branch?
Yes, this change belongs to vNext branch, however the readme.md is quite different there. I would suggest adding a new section "Working with assets" that would contain info about dynamic assets vs strongly typed assets and a simple code sample on how to create assets in both categories.

@Simply007 what do you think?

There is also a https://github.com/Kentico/kontent-management-sdk-net/blob/vNext/Kentico.Kontent.Management.Tests/Unit/CodeSamples/Readme.cs file with all existing code samples for  README to just verify the code is compilable.

Okay, I added "Working with assets" section with two examples. The PR is now pointed to the vNext branch. The unit tests were updated.


Update Code-Scanning.yml jobs to use Node.js 20

actions/checkout to v4 and microsoft/setup-msbuild to v2

I may be creating more work here, but we should make sure CodeQL workflow is aligned as close as reasonably possible with https://github.com/microsoft/Windows-driver-samples/blob/main/.github/workflows/ci.yml and https://github.com/microsoft/Windows-driver-samples/blob/main/.github/workflows/ci-pr.yml .  Those two workflows uses actions that you are updating, so we should also update them for those two files.   Jacob you could take a stab at this and coordinate with @NeoAdonis  .
In hindsight I see similar issue here: https://github.com/microsoft/Windows-driver-samples/actions/runs/8133471231 and here: https://github.com/microsoft/Windows-driver-samples/actions/runs/8133038769 .

I agree with this observation Jakob made. Thanks for the heads-up!
@jacob-ronstadt : Because you have a PR already, could you implement the same change in both ci.yml and ci-pr.yml, please? I could create a separate PR if you prefer that instead.

@NeoAdonis @JakobL-MSFT Updated!


[5.1] Import Diactoros response class

An ErrorException is raised when requesting the Psr\Http\Message\ResponseInterface abstract instance from the Laravel container. The class is not found because it is not imported into the file scope. Add a use statement to import the class into this file.

:beers:


Cannot have Diferent layout of terminal in diferent windows

VSCode Version: Code 1.18.1 (929bacba01ef658b873545e26034d1a8067445e9, 2017-11-16T18:32:36.023Z)
OS Version: Windows_NT x64 6.3.9600
Extensions:

Extension
Author (truncated)
Version

unique-lines
bib
1.0.0

npm-intellisense
chr
1.3.0

jsrefactor
cms
2.1.3

jshint
dba
0.10.15

vscode-stylesheet-formatter
dba
0.2.0

vscode-uriencode
die
0.0.1

githistory
don
0.2.3

jquerysnippets
don
0.0.1

xml
Dot
1.9.2

javac-linter
fau
1.2.6

JSDocTagComplete
Hoo
0.0.2

pgsql-html
hub
0.0.7

java-properties
ith
0.0.2

guid
kos
0.0.1

markdown-shortcuts
mdi
0.8.1

HTMLHint
mka
0.4.0

prettify-json
moh
0.0.3

vscode-scss
mrm
0.6.2

csharp
ms-
1.13.1

jscs
ms-
0.1.9

debugger-for-chrome
msj
3.5.0

vscode-sql-beautify
sen
0.0.4

markdown-preview-enhanced
shd
0.3.1

stylelint
shi
0.31.0

addDocComments
ste
0.0.8

sort-lines
Tyr
1.3.0

gitblame
wad
2.2.0

bootstrap-3-snippets
wcw
0.1.0

Steps to Reproduce:

Open 2 windows
Open terminal for both
Switch to Vertical view on one
Expected only one to change, but both changed.

Fixed in latest stable.

Nope, I have the latest stable version.
Maybe it's not released?

It will be released in a couple of days.
If you need it imediatly get the latest vscode insiders

Ok, thanks.


Support deleting search index without deleting documents

https://github.com/RedisVentures/redisvl/blob/e3a97e9ed3c4adb6f766ed475cf40ae8cdb98336/redisvl/index.py#L88

This should be possible through the SearchIndex interface presented in #13


[Event Request] codeunit 99000809 "Planning Line Management" - OnAfterSetPlanningLevelCode

local procedure CreatePlanningComponentFromProdBOM(var PlanningComponent: Record "Planning Component"; ReqLine: Record "Requisition Line"; ProdBOMLine: Record "Production BOM Line"; CompSKU: Record "Stockkeeping Unit"; LineQtyPerUOM: Decimal; ItemQtyPerUOM: Decimal)
    ...
        "Flushing Method" := CompSKU."Flushing Method";
        //A200F0008.Event20.04.os
        //if (SKU."Manufacturing Policy" = SKU."Manufacturing Policy"::"Make-to-Order") and
        //   (CompSKU."Manufacturing Policy" = CompSKU."Manufacturing Policy"::"Make-to-Order") and
        //   (CompSKU."Replenishment System" = CompSKU."Replenishment System"::"Prod. Order")
        //then
        //A200F0008.Event20.04.oe
        if SetPlanningLevelCode(PlanningComponent, ProdBOMLine, SKU, CompSKU) then
            "Planning Level Code" := ReqLine."Planning Level" + 1;

local procedure SetPlanningLevelCode(var PlanningComponent: Record "Planning Component"; var ProdBOMLine: Record "Production BOM Line"; var SKU: Record "Stockkeeping Unit"; var ComponentSKU: Record "Stockkeeping Unit") Result: Boolean
begin
    //A200F0008.Event20.04.ns
    Result :=
        (SKU."Manufacturing Policy" = SKU."Manufacturing Policy"::"Make-to-Order") and
        (ComponentSKU."Manufacturing Policy" = ComponentSKU."Manufacturing Policy"::"Make-to-Order") and
        (ComponentSKU."Replenishment System" = ComponentSKU."Replenishment System"::"Prod. Order");

    OnAfterSetPlanningLevelCode(PlanningComponent, ProdBOMLine, SKU, ComponentSKU, Result);
    //A200F0008.Event20.04.ne
end;

[IntegrationEvent(false, false)]
local procedure OnAfterSetPlanningLevelCode(var PlanningComponent: Record "Planning Component"; var ProdBOMLine: Record "Production BOM Line"; var SKU: Record "Stockkeeping Unit"; var ComponentSKU: Record "Stockkeeping Unit"; var Result: Boolean)
begin
    //A200F0008.Event20.04
end;

Thanks for reporting this. We agree, and we’ll publish a fix asap, either in an update for the current version or in the next major release. Please do not reply to this, as we do not monitor closed issues. If you have follow-up questions or requests, please create a new issue where you reference this one.
Build ID: 45914.


Two Brown eggs in list

I think 176 should be a white egg?
https://github.com/MouseyPounds/stardew-predictor/blob/ae37d362e96eaf2aa1c429a203f7ce44402eb12c/stardew-predictor.js#L1199

Right you are. Thanks. I'll push out an update for that a bit later today.


Restliche Modelle evaluieren

continued here:
https://github.com/orgs/AdversarialAttacks/projects/1/views/6?pane=issue&itemId=60186419


Unable to make sample skills (that require auth) to work with Bot Composer

I'm trying to connect an existing remote skill in Azure (Email Skill in github sample) to a bot developed in composer. While the skill connects successfully, it doesn't respond to any of the messages. This happens only for skills that requires authentication. Other skills that don't require auth works fine. I'm following the steps given in the documentation exactly as instructed (https://docs.microsoft.com/en-us/composer/how-to-connect-to-a-skill). Am I doing anything wrong?

@dmvtech Can you take a look at this?

@csnarain, thank you for your patience. A couple basic questions for you:

Are you receiving any error messages that you can post?
Are you certain you are adding the MSAppId's as strings into the AllowedCallers array found in the project's settings (ref. here).

Closing due to lack of activity.

Closed due to lack of activity.


lodash: changed _.escape(), _.escapeRegExp() and _.unescape() methods…

… (added to a chainable wrapper)
https://lodash.com/docs#escape
https://lodash.com/docs#unescape
https://lodash.com/docs#escapeRegExp
https://lodash.com/docs#_ (a chainable wrapper description)

lodash/lodash.d.ts
to author(@bczengel). could you review this PR?
:+1: or :-1:?
check list

[ ] pass the Travic-CI test?

:+1:

@bczengel thanks!
@chrootsu thanks mate!


Better sampling

@amj i haven't actually run this code.

/retest

Yeah, 0.02 comes from 4 / 200 being the assumption we were making previously in this code. I think it should be factored out more explicitly in terms of the hyperparameters of the run (what is trailing window size, etc.)
Speaking of which, what happened to our slow start thing - I forget if we wrote code for that?

Got it.  "Slow start" is right here: https://github.com/tensorflow/minigo/blob/master/example_buffer.py#L184
it's been in the v10 run :)

Ah, I see. But you can't change the window size without also changing the sampling ratio, because then your chunks won't fill up completely? Or something like that.
shrug, I guess it's working so I'm not going to look too closely at this particular file.

I also did run the integration tests and fixed some stuff, so it should be good.

i'm really not sure about this change.  In particular, i think the assumption of "50 generations in the window" may be pretty far off.  We can try it on v11 but i have some real reservations about how this will work...

The assumption being made here is identical to the assumption that was
previously being made (4 moves from a game that is 200 long on average)
On Fri, Sep 7, 2018 at 4:15 PM Andrew Jackson<EMAIL_ADDRESS>wrote:

i'm really not sure about this change. In particular, i think the
assumption of "50 generations in the window" may be pretty far off. We can
try it on v11 but i have some real reservations about how this will work...
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
https://github.com/tensorflow/minigo/pull/404#issuecomment-419553656,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABQlFn9H8N6S3u89YmIRnvHdoXOLTg1Iks5uYtPlgaJpZM4WSqEr
.

Not quite:  4 moves per game * a window of 500k games = the 2M samples required for 1k steps per checkpoint.


Dockerize big-dipper

Description
Dockerized the application to make deployment easier.
Checklist

[x] Added an entry to the CHANGELOG.md file.
[ ] Re-reviewed Files changed in the Github PR explorer.

@orkunkl thank you!

thank you for making this beautiful application 🙇♂ @kwunyeung

@davepuchyr I think the last 4 commits are better be in a separate branch as those code changes are quite specific to IOV. We are currently in organizing the versioning. The master branch will soon hold the latest code targeting to v0.38.x and I will merge the docker file after that. Thanks!

@davepuchyr I think the last 4 commits are better be in a separate branch as those code changes are quite specific to IOV. We are currently in organizing the versioning. The master branch will soon hold the latest code targeting to v0.38.x and I will merge the docker file after that. Thanks!

I wasn't aware of this PR.  Indeed, all my commits are very IOV specific and I had no intention of pushing them into your repo.  Sorry for causing confusion.

@davepuchyr thanks but the docker file from @orkunkl is a good one. 🎉

Sorry for the confusion. It's my bad. I will create a PR with only dockerfile commit in the next days. For now closing the PR.


Segfault during fetch

I am not sure what the exact condition is, as the code works in some cases. It fails on aarch64.
[Current thread is 1 (Thread 0xffff8e7b7c00 (LWP 5))]
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.34-100.el9_4.2.aarch64 libgcc-11.4.1-3.el9.alma.1.aarch64
(gdb) where
#0  0x0000aaaabf1dcdc4 in git_commit_list_insert_by_date ()
#1  0x0000aaaabf1925c8 in git_revwalk.push_commit ()
#2  0x0000aaaabf192b24 in git_revwalk.push_glob ()
#3  0x0000aaaabf1b82a8 in git_smart.negotiate_fetch ()
#4  0x0000aaaabf1e0510 in git_fetch_negotiate ()
#5  0x0000aaaabf187d54 in git_remote.download ()
#6  0x0000aaaabf188ff4 in git_remote_fetch ()
#7  0x0000aaaabe8f33ac in git2::remote::Remote::fetch ()
#8  0x0000aaaabe8fa1c4 in tracing::span::Span::in_scope ()
#9  0x0000aaaabe743be0 in trustify_module_importer::server::common::walker::git::GitWalker<H,T>::run_sync ()
#10 0x0000aaaabe7d61f0 in tokio::runtime::task::core::Core<T,S>::poll ()
#11 0x0000aaaabe841ca0 in tokio::runtime::task::harness::Harness<T,S>::poll ()
#12 0x0000aaaac0087514 in std::sys_common::backtrace::__rust_begin_short_backtrace ()
#13 0x0000aaaac0067af4 in core::ops::function::FnOnce::call_once{{vtable.shim}} () at library/core/src/panic.rs:106
#14 0x0000aaaac010c148 in alloc::boxed::{impl#47}::call_once<(), dyn core::ops::function::FnOnce<(), Output=()>, alloc::alloc::Global> () at library/alloc/src/boxed.rs:2020
#15 alloc::boxed::{impl#47}::call_once<(), alloc::boxed::Box<dyn core::ops::function::FnOnce<(), Output=()>, alloc::alloc::Global>, alloc::alloc::Global> () at library/alloc/src/boxed.rs:2020
#16 std::sys::pal::unix::thread::{impl#2}::new::thread_start () at library/std/src/sys/pal/unix/thread.rs:108
#17 0x0000ffff8ec5e698 in start_thread () from /lib64/libc.so.6
#18 0x0000ffff8ecc8bdc in thread_start () from /lib64/libc.so.6

I assume it is using the vendored version (default build flags, compiled with cross, which doesn't have libgit2 installed afaik). The output of ldd is:
        linux-vdso.so.1 (0x0000ffffb36d2000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000ffffb3664000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x0000ffffb3643000)
        libm.so.6 => /lib64/libm.so.6 (0x0000ffffae95f000)
        libdl.so.2 => /lib64/libdl.so.2 (0x0000ffffae93e000)
        libc.so.6 => /lib64/libc.so.6 (0x0000ffffae780000)
        /lib/ld-linux-aarch64.so.1 (0x0000ffffb3695000)

I am using git2 0.18.3 and libgit2-sys 0.16.2+1.7.2

Can you create a reproduction? Otherwise I don't think we'll be able to help.

I briefly tried that, but didn't succeed and went in a different direction. If that helps, I'll try again and see if I can get there. Because on that single installation, it fails 100% of the time.

Just a quick update, I am trying to narrow it down. Using the original application, it seems to work when using cargo to compile and run it. Using cross to compile it (using the similar or same Ubuntu version the cross container image should have) results in a segfault. Always at the same location.

I do have a reproducer. It's a bit complex and a bit weird. It seems to include cross and aarch64: https://github.com/ctron/git2-repro

The main difference I figured out so far is that cross actually uses an Ubuntu 16.04 based image, while I was using an Ubuntu 20.04 VM to reproduce this. cross updated the container image's base layer, but it seems like they never released that.

Since everything is vendored and static, I don't understand what flows into the final binary that makes a difference.

If I swap out the build image with the edge version (which is built on what is in main git) then works.
I don't know which parts influence the final binary to misbehave, as to my understanding everything should be vendored.
On the other side, I am not sure trying to fix an issue which is caused by an 8 year old distribution makes sense.


moveTo always results in NO_PATH_FOUND

hey there, as the title suggests when I try to use moveTo on either the player or an NPC I always get above issue which I see after subscribing to the method.
any ideas where I should look at (most likely I'm doing something wrong) to track the issue down?

alright I'm entirely sure I've tested that but whatsoever. Seems the only reason was that I was pointing the NPC to a blocked tile. So since the target would collide it determined not to move. Guess I'll have to calculate the next free neighbor.
Would you see some of these helper utils fit the grid-engine? Like getFreeAdjectentTiles(tile, charId). CharId included because it would perhaps need to check collision groups as well

Hey @zewa666, do I understand correctly that you are looking for a convenient way to move it to the next free neighbor instead? There is already a configuration for the moveTo method. Just pass a MoveToConfig object with NoPathFoundStrategy set to "CLOSEST_REACHABLE".

So the question in the end is how much helpers do you want to offer for typical use cases or whether consumers are supposed to do those parts themselves using those tiny building blocks like isBlocked

The general strategy of prioritizing for GridEngine is to first provide all basic building blocks that offer a maximum amount of flexibility within the scope of the project. And then come convenience features that make stuff easier.
You reminded me that I forgot to add the collision groups parameter to the docs of isBlocked. 👍

awesome, thx for the heads up with CLOSEST_REACHABLE. was fun to build it by myself but I'll gladly switch to your premade solution :)
also thanks for clarifying your strategy with the engine.


Cannot produce results using the pretrained model

Hi,
I just read your paper and appreciate your well-organized code very much. But I cannot produce results using the pre-trained model.

I am not quite sure where the problem is. Did I use the wrong command?
python -u -m dmn_pytorch.train
--data /home/xxx/dms_data
--dataset unc
--val testA
--backend dpn92
--num-filters 10
--lang-layers 3
--mix-we
--save-folder ./checkpoints
--snapshot /home/xxx/DMS/checkpoints/dmn_unc_weights.pth
--epochs 0
--eval-first

By the way, I noticed that the default batch size in the program is set to 1. But when I try to increase the batch size value, I got
RuntimeError: stack expects each tensor to be equal size, but got [3, 512, 512] at entry 0 and [3, 342, 512] at entry 1
It seems that the code kept the aspect ratio of the original image when doing resize so that images in the same batch are of different sizes. I wonder that was your model trained with the batch size of 1? Thank you!

plus --high-res

@ntuLC Sorry for the late reply. Please take a look at the discussion of https://github.com/BCV-Uniandes/DMS/issues/21#issuecomment-450692135 and see if it solves this one. As @13331112522, you might be missing the --high-res flag, as the pretrained weights are high-resolution ones. Also, please take into account that the dependencies of this project are very old and values may vary with latest releases of PyTorch/SRU.
Regarding the question about the batch size, we had to train our model with a batch size of 1, due to memory constraints and also due to the dynamic convolution computations which do not allow batch dimension computation.


New OutputData type

Abstract
This output is for including arbitrary data within a transaction. This allows users and developers to include arbitrary data that can be signed over that cannot be included in a script, input, smart contract or within predicate code.
Note, this output is not spendable.
Prior Art
https://en.bitcoin.it/wiki/OP_RETURN

Why can't we use predicate_data or script_data to store arbitrary data?

One potential use case for an output type like this would be providing the preimage to an asset ID to determine the contract ID without having to annoyingly include that data as an argument in a deposit method for things like AMMs. Instead, you can have a function included in the standard library which just scans the outputs for this preimage in a specific output data.

People can still use this new output to store different kinds of data(not only the preimage of the asset id), so SDK should understand the purpose of each output somehow. I think that if your code requires a preimage of the asset id, then you should provide it as an argument. Otherwise, it is chaos with random outputs.


Added OrdersService

I've added OrdersService and refactored SandboxService to conform OrdersService protocol.
Please, publish 0.3.1 version after merge if it is possible :)

@AndreVasilev  Thanks for a new PR! After this PR I will update and release new version)


Installation Issue

I was able to get the FFU on my USB. When I boot to the USB, it will open a prompt and load through imaging, then once it gets to 100 I get this message:
Windows could not parse or process unattend answer file [C:\Windows\Panther\Unattend\unattend.xml] for pass [auditUser]. The settings specified in the answer file cannot be applied. The error was detected while processing settings for component [Microsoft-Windows-Deployment].
Tried redoing it to no avail. I've attached both the dism and script logs. Any help would be appreciated.
dism.log
ScriptLog.txt

do you have the script log from BuildFFUVM.ps1? that would show if there were any issues when that ran that could result in this error.

Yes I've attached it.
On Thu, Jun 20, 2024 at 6:23 AM Mike Kelly @.***> wrote:

do you have the script log from BuildFFUVM.ps1? that would show if
there were any issues when that ran that could result in this error.
—
Reply to this email directly, view it on GitHub
https://github.com/rbalsleyMSFT/FFU/issues/29#issuecomment-2180333304,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/BJJOXZXT4O2YKYXJ5K24CELZIKUTPAVCNFSM6AAAAABJS27TZWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOBQGMZTGMZQGQ
.
You are receiving this because you authored the thread.Message ID:
@.***>

Can you attach the unattend.xml file from the USB drive? Should be in a folder called unattend on the deploy partition.

Also attach the c:\FFUDevelopment\FFUDevelopment.log from the machine you build the FFU from.

I've attached unattend from the USB. Also attached the original unattend in
the BuildFFUunattend folder (the 2k xml file) if it will help.
Also got the development.log and the BuildFFUVM file included, but have to
send the BuildFFUVM file as txt because gmail is blocking ps1 files.
On Thu, Jun 20, 2024 at 11:33 AM rbalsleyMSFT @.***>
wrote:

Also attach the c:\FFUDevelopment\FFUDevelopment.log from the machine you
build the FFU from.
—
Reply to this email directly, view it on GitHub
https://github.com/rbalsleyMSFT/FFU/issues/29#issuecomment-2180992488,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/BJJOXZVT5FS23RYN7L4OQI3ZILY4JAVCNFSM6AAAAABJS27TZWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOBQHE4TENBYHA
.
You are receiving this because you authored the thread.Message ID:
@.***>

#Requires -Modules Hyper-V, Storage
#Requires -PSEdition Desktop
#Requires -RunAsAdministrator
<#
.SYNOPSIS
A PowerShell script to create a Windows 10/11 FFU file.
.DESCRIPTION
This script creates a Windows 10/11 FFU and USB drive to help quickly get a Windows device reimaged. FFU can be customized with drivers, apps, and additional settings.
.PARAMETER ISOPath
Path to the Windows 10/11 ISO file.
.PARAMETER WindowsSKU
Edition of Windows 10/11 to be installed, e.g., accepted values are: 'Home', 'Home N', 'Home Single Language', 'Education', 'Education N', 'Pro', 'Pro N', 'Pro Education', 'Pro Education N', 'Pro for Workstations', 'Pro N for Workstations', 'Enterprise', 'Enterprise N'
.PARAMETER FFUDevelopmentPath
Path to the FFU development folder (default is C:\FFUDevelopment).
.PARAMETER InstallApps
When set to $true, the script will create an Apps.iso file from the $FFUDevelopmentPath\Apps folder. It will also create a VM, mount the Apps.ISO, install the Apps, sysprep, and capture the VM. When set to $False, the FFU is created from a VHDX file. No VM is created.
.PARAMETER InstallOffice
Install Microsoft Office if set to $true. The script will download the latest ODT and Office files in the $FFUDevelopmentPath\Apps\Office folder and install Office in the FFU via VM
.PARAMETER InstallDrivers
Install device drivers from the specified $FFUDevelopmentPath\Drivers folder if set to $true. Download the drivers and put them in the Drivers folder. The script will recurse the drivers folder and add the drivers to the FFU.
.PARAMETER Memory
Amount of memory to allocate for the virtual machine. Recommended to use 8GB if possible, especially for Windows 11. Use 4GB if necesary.
.PARAMETER Disksize
Size of the virtual hard disk for the virtual machine. Default is a 30GB dynamic disk.
.PARAMETER Processors
Number of virtual processors for the virtual machine. Recommended to use at least 4.
.PARAMETER VMSwitchName
Name of the Hyper-V virtual switch. If $InstallApps is set to $true, this must be set. This is required to capture the FFU from the VM. The default is external, but you will likely need to change this.
.PARAMETER VMLocation
Default is $FFUDevelopmentPath\VM. This is the location of the VHDX that gets created where Windows will be installed to.
.PARAMETER FFUPrefix
Prefix for the generated FFU file. Default is _FFU
.PARAMETER FFUCaptureLocation
Path to the folder where the captured FFU will be stored. Default is $FFUDevelopmentPath\FFU
.PARAMETER ShareName
Name of the shared folder for FFU capture. The default is FFUCaptureShare. This share will be created with rights for the user account. When finished, the share will be removed.
.PARAMETER Username
Username for accessing the shared folder. The default is ffu_user. The script will auto create the account and password. When finished, it will remove the account.
.PARAMETER VMHostIPAddress
IP address of the Hyper-V host for FFU capture. If $InstallApps is set to $true, this parameter must be configured. You must manually configure this. The script will not auto detect your IP (depending on your network adapters, it may not find the correct IP).
.PARAMETER CreateCaptureMedia
When set to $true, this will create WinPE capture media for use when $InstallApps is set to $true. This capture media will be automatically attached to the VM and the boot order will be changed to automate the capture of the FFU.
.PARAMETER CreateDeploymentMedia
When set to $true, this will create WinPE deployment media for use when deploying to a physical device.
.PARAMETER OptionalFeatures
Provide a semi-colon separated list of Windows optional features you want to include in the FFU (e.g. netfx3;TFTP)
.PARAMETER ProductKey
Product key for the Windows 10/11 edition specified in WindowsSKU. This will overwrite whatever SKU is entered for WindowsSKU. Recommended to use if you want to use a MAK or KMS key to activate Enterprise or Education. If using VL media instead of consumer media, you'll want to enter a MAK or KMS key here.
.PARAMETER BuildUSBDrive
When set to $true, will partition and format a USB drive and copy the captured FFU to the drive. If you'd like to customize the drive to add drivers, provisioning packages, name prefix, etc. You'll need to do that afterward.
.PARAMETER WindowsRelease
Integer value of 10 or 11. This is used to identify which release of Windows to download. Default is 11.
.PARAMETER WindowsVersion
String value of the Windows version to download. This is used to identify which version of Windows to download. Default is 23h2.
.PARAMETER WindowsArch
String value of x86 or x64. This is used to identify which architecture of Windows to download. Default is x64.
.PARAMETER WindowsLang
String value in language-region format (e.g. en-us). This is used to identify which language of media to download. Default is en-us.
.PARAMETER MediaType
String value of either business or consumer. This is used to identify which media type to download. Default is consumer.
.PARAMETER LogicalSectorBytes
unit32 value of 512 or 4096. Not recommended to change from 512. Might be useful for 4kn drives, but needs more testing. Default is 512.
.PARAMETER Optimize
When set to $true, will optimize the FFU file. Default is $true.
.PARAMETER CopyDrivers
When set to $true, will copy the drivers from the $FFUDevelopmentPath\Drivers folder to the Drivers folder on the deploy partition of the USB drive. Default is $false.
.PARAMETER CopyPEDrivers
When set to $true, will copy the drivers from the $FFUDevelopmentPath\PEDrivers folder to the WinPE deployment media. Default is $false.
.PARAMETER RemoveFFU
When set to $true, will remove the FFU file from the $FFUDevelopmentPath\FFU folder after it has been copied to the USB drive. Default is $false.
.PARAMETER UpdateLatestCU
When set to $true, will download and install the latest cumulative update for Windows 10/11. Default is $false.
.PARAMETER UpdateLatestNet
When set to $true, will download and install the latest .NET Framework for Windows 10/11. Default is $false.
.PARAMETER UpdateLatestDefender
When set to $true, will download and install the latest Windows Defender definitions and Defender platform update. Default is $false.
.PARAMETER UpdateEdge
When set to $true, will download and install the latest Microsoft Edge for Windows 10/11. Default is $false.
.PARAMETER UpdateOneDrive
When set to $true, will download and install the latest OneDrive for Windows 10/11 and install it as a per machine installation instead of per user. Default is $false.
.PARAMETER CopyPPKG
When set to $true, will copy the provisioning package from the $FFUDevelopmentPath\PPKG folder to the Deployment partition of the USB drive. Default is $false.
.PARAMETER CopyUnattend
When set to $true, will copy the $FFUDevelopmentPath\Unattend folder to the Deployment partition of the USB drive. Default is $false.
.PARAMETER CopyAutopilot
When set to $true, will copy the $FFUDevelopmentPath\Autopilot folder to the Deployment partition of the USB drive. Default is $false.
.PARAMETER CompactOS
When set to $true, will compact the OS when building the FFU. Default is $true.
.PARAMETER CleanupCaptureISO
When set to $true, will remove the WinPE capture ISO after the FFU has been captured. Default is $true.
.PARAMETER CleanupDeployISO
When set to $true, will remove the WinPE deployment ISO after the FFU has been captured. Default is $true.
.PARAMETER CleanupAppsISO
When set to $true, will remove the Apps ISO after the FFU has been captured. Default is $true.
.EXAMPLE
Command line for most people who want to download the latest Windows 11 Pro x64 media in English (US) with the latest Windows Cumulative Update, .NET Framework, Defender platform and definition updates, Edge, OneDrive, and Office/M365 Apps. It will also copy drivers to the FFU. This can take about 40 minutes to create the FFU due to the time it takes to download and install the updates.
.\BuildFFUVM.ps1 -WindowsSKU 'Pro' -Installapps $true -InstallOffice $true -InstallDrivers $true -VMSwitchName 'Name of your VM Switch in Hyper-V' -VMHostIPAddress 'Your IP Address' -CreateCaptureMedia $true -CreateDeploymentMedia $true -BuildUSBDrive $true -UpdateLatestCU $true -UpdateLatestNet $true -UpdateLatestDefender $true -UpdateEdge $true -UpdateOneDrive $true -verbose
Command line for most people who want to create an FFU with Office and drivers and have downloaded their own ISO. This assumes you have copied this script and associated files to the C:\FFUDevelopment folder. If you need to use another drive or folder, change the -FFUDevelopment parameter (e.g. -FFUDevelopment 'D:\FFUDevelopment')
.\BuildFFUVM.ps1 -ISOPath 'C:\path_to_iso\Windows.iso' -WindowsSKU 'Pro' -Installapps $true -InstallOffice $true -InstallDrivers $true -VMSwitchName 'Name of your VM Switch in Hyper-V' -VMHostIPAddress 'Your IP Address' -CreateCaptureMedia $true -CreateDeploymentMedia $true -BuildUSBDrive $true -verbose
Command line for those who just want a FFU with no drivers, apps, or Office and have downloaded their own ISO.
.\BuildFFUVM.ps1 -ISOPath 'C:\path_to_iso\Windows.iso' -WindowsSKU 'Pro' -Installapps $false -InstallOffice $false -InstallDrivers $false -CreateCaptureMedia $false -CreateDeploymentMedia $true -BuildUSBDrive $true -verbose
Command line for those who just want a FFU with Apps and drivers, no Office and have downloaded their own ISO.
.\BuildFFUVM.ps1 -ISOPath 'C:\path_to_iso\Windows.iso' -WindowsSKU 'Pro' -Installapps $true -InstallOffice $false -InstallDrivers $true -VMSwitchName 'Name of your VM Switch in Hyper-V' -VMHostIPAddress 'Your IP Address' -CreateCaptureMedia $true -CreateDeploymentMedia $true -BuildUSBDrive $true -verbose
Command line for those who want to download the latest Windows 11 Pro x64 media in English (US) and install the latest version of Office and drivers.
.\BuildFFUVM.ps1 -WindowsSKU 'Pro' -Installapps $true -InstallOffice $true -InstallDrivers $true -VMSwitchName 'Name of your VM Switch in Hyper-V' -VMHostIPAddress 'Your IP Address' -CreateCaptureMedia $true -CreateDeploymentMedia $true -BuildUSBDrive $true -verbose
Command line for those who want to download the latest Windows 11 Pro x64 media in French (CA) and install the latest version of Office and drivers.
.\BuildFFUVM.ps1 -WindowsSKU 'Pro' -Installapps $true -InstallOffice $true -InstallDrivers $true -VMSwitchName 'Name of your VM Switch in Hyper-V' -VMHostIPAddress 'Your IP Address' -CreateCaptureMedia $true -CreateDeploymentMedia $true -BuildUSBDrive $true -WindowsRelease 11 -WindowsArch 'x64' -WindowsLang 'fr-ca' -MediaType 'consumer' -verbose
Command line for those who want to download the latest Windows 11 Pro x64 media in English (US) and install the latest version of Office and drivers.
.\BuildFFUVM.ps1 -WindowsSKU 'Pro' -Installapps $true -InstallOffice $true -InstallDrivers $true -VMSwitchName 'Name of your VM Switch in Hyper-V' -VMHostIPAddress 'Your IP Address' -CreateCaptureMedia $true -CreateDeploymentMedia $true -BuildUSBDrive $true -verbose
.NOTES
Additional notes about your script.
.LINK
https://github.com/rbalsleyMSFT/FFU
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $false, Position = 0)]
[ValidateScript({ Test-Path $_ })]
[string]$ISOPath,
[ValidateScript({
$allowedSKUs = @('Home', 'Home N', 'Home Single Language', 'Education', 'Education N', 'Pro', 'Pro N', 'Pro Education', 'Pro Education N', 'Pro for Workstations', 'Pro N for Workstations', 'Enterprise', 'Enterprise N')
if ($allowedSKUs -contains $) { $true } else { throw "Invalid WindowsSKU value. Allowed values: $($allowedSKUs -join ', ')" }
return $true
})]
[string]$WindowsSKU = 'Pro',
[ValidateScript({ Test-Path $ })]
[string]$FFUDevelopmentPath = $PSScriptRoot,
[bool]$InstallApps,
[bool]$InstallOffice,
[Parameter(Mandatory = $false)]
[ValidateScript({
if ($_ -and (!(Test-Path -Path '.\Drivers') -or ((Get-ChildItem -Path '.\Drivers' -Recurse | Measure-Object -Property Length -Sum).Sum -lt 1MB))) {
throw 'InstallDrivers is set to $true, but either the Drivers folder is missing or empty'
}
return $true
})]
[bool]$InstallDrivers,
[uint64]$Memory = 4GB,
[uint64]$Disksize = 30GB,
[int]$Processors = 4,
[string]$VMSwitchName,
[string]$VMLocation,
[string]$FFUPrefix = 'FFU',
[string]$FFUCaptureLocation,
[String]$ShareName = "FFUCaptureShare",
[string]$Username = "ffu_user",
[Parameter(Mandatory = $false)]
[string]$VMHostIPAddress,
[bool]$CreateCaptureMedia = $true,
[bool]$CreateDeploymentMedia,
[ValidateScript({
$allowedFeatures = @("Windows-Defender-Default-Definitions", "Printing-PrintToPDFServices-Features", "Printing-XPSServices-Features", "TelnetClient", "TFTP",
"TIFFIFilter", "LegacyComponents", "DirectPlay", "MSRDC-Infrastructure", "Windows-Identity-Foundation", "MicrosoftWindowsPowerShellV2Root", "MicrosoftWindowsPowerShellV2",
"SimpleTCP", "NetFx4-AdvSrvs", "NetFx4Extended-ASPNET45", "WCF-Services45", "WCF-HTTP-Activation45", "WCF-TCP-Activation45", "WCF-Pipe-Activation45", "WCF-MSMQ-Activation45",
"WCF-TCP-PortSharing45", "IIS-WebServerRole", "IIS-WebServer", "IIS-CommonHttpFeatures", "IIS-HttpErrors", "IIS-HttpRedirect", "IIS-ApplicationDevelopment", "IIS-Security",
"IIS-RequestFiltering", "IIS-NetFxExtensibility", "IIS-NetFxExtensibility45", "IIS-HealthAndDiagnostics", "IIS-HttpLogging", "IIS-LoggingLibraries", "IIS-RequestMonitor",
"IIS-HttpTracing", "IIS-URLAuthorization", "IIS-IPSecurity", "IIS-Performance", "IIS-HttpCompressionDynamic", "IIS-WebServerManagementTools", "IIS-ManagementScriptingTools",
"IIS-IIS6ManagementCompatibility", "IIS-Metabase", "WAS-WindowsActivationService", "WAS-ProcessModel", "WAS-NetFxEnvironment", "WAS-ConfigurationAPI", "IIS-HostableWebCore",
"WCF-HTTP-Activation", "WCF-NonHTTP-Activation", "IIS-StaticContent", "IIS-DefaultDocument", "IIS-DirectoryBrowsing", "IIS-WebDAV", "IIS-WebSockets", "IIS-ApplicationInit",
"IIS-ISAPIFilter", "IIS-ISAPIExtensions", "IIS-ASPNET", "IIS-ASPNET45", "IIS-ASP", "IIS-CGI", "IIS-ServerSideIncludes", "IIS-CustomLogging", "IIS-BasicAuthentication",
"IIS-HttpCompressionStatic", "IIS-ManagementConsole", "IIS-ManagementService", "IIS-WMICompatibility", "IIS-LegacyScripts", "IIS-LegacySnapIn", "IIS-FTPServer", "IIS-FTPSvc",
"IIS-FTPExtensibility", "MSMQ-Container", "MSMQ-DCOMProxy", "MSMQ-Server", "MSMQ-ADIntegration", "MSMQ-HTTP", "MSMQ-Multicast", "MSMQ-Triggers", "IIS-CertProvider",
"IIS-WindowsAuthentication", "IIS-DigestAuthentication", "IIS-ClientCertificateMappingAuthentication", "IIS-IISCertificateMappingAuthentication", "IIS-ODBCLogging",
"NetFx3", "SMB1Protocol-Deprecation", "MediaPlayback", "WindowsMediaPlayer", "Client-DeviceLockdown", "Client-EmbeddedShellLauncher", "Client-EmbeddedBootExp",
"Client-EmbeddedLogon", "Client-KeyboardFilter", "Client-UnifiedWriteFilter", "HostGuardian", "MultiPoint-Connector", "MultiPoint-Connector-Services", "MultiPoint-Tools"
, "AppServerClient", "SearchEngine-Client-Package", "WorkFolders-Client", "Printing-Foundation-Features", "Printing-Foundation-InternetPrinting-Client",
"Printing-Foundation-LPDPrintService", "Printing-Foundation-LPRPortMonitor", "HypervisorPlatform", "VirtualMachinePlatform", "Microsoft-Windows-Subsystem-Linux",
"Client-ProjFS", "Containers-DisposableClientVM", 'Containers-DisposableClientVM', 'Microsoft-Hyper-V-All', 'Microsoft-Hyper-V', 'Microsoft-Hyper-V-Tools-All',
'Microsoft-Hyper-V-Management-PowerShell', 'Microsoft-Hyper-V-Hypervisor', 'Microsoft-Hyper-V-Services', 'Microsoft-Hyper-V-Management-Clients', 'DataCenterBridging',
'DirectoryServices-ADAM-Client', 'Windows-Defender-ApplicationGuard', 'ServicesForNFS-ClientOnly', 'ClientForNFS-Infrastructure', 'NFS-Administration', 'Containers', 'Containers-HNS',
'Containers-SDN', 'SMB1Protocol', 'SMB1Protocol-Client', 'SMB1Protocol-Server', 'SmbDirect')
$inputFeatures = $ -split ';'
foreach ($feature in $inputFeatures) {
if (-not ($allowedFeatures -contains $feature)) {
throw "Invalid optional feature '$feature'. Allowed values: $($allowedFeatures -join ', ')"
}
}
return $true
})]
[string]$OptionalFeatures,
[string]$ProductKey,
[bool]$BuildUSBDrive,
[Parameter(Mandatory = $false)]
[ValidateSet(10, 11)]
[int]$WindowsRelease = 11,
[Parameter(Mandatory = $false)]
[string]$WindowsVersion = '23h2',
[Parameter(Mandatory = $false)]
[ValidateSet('x86', 'x64', 'arm64')]
[string]$WindowsArch = 'x64',
[ValidateScript({
$allowedLang = @('ar-sa', 'bg-bg', 'cs-cz', 'da-dk', 'de-de', 'el-gr', 'en-gb', 'en-us', 'es-es', 'es-mx', 'et-ee', 'fi-fi', 'fr-ca', 'fr-fr', 'he-il', 'hr-hr', 'hu-hu',
'it-it', 'ja-jp', 'ko-kr', 'lt-lt', 'lv-lv', 'nb-no', 'nl-nl', 'pl-pl', 'pt-br', 'pt-pt', 'ro-ro', 'ru-ru', 'sk-sk', 'sl-si', 'sr-latn-rs', 'sv-se', 'th-th', 'tr-tr', 'uk-ua',
'zh-cn', 'zh-tw')
if ($allowedLang -contains $) { $true } else { throw "Invalid WindowsLang value. Allowed values: $($allowedLang -join ', ')" }
return $true
})]
[Parameter(Mandatory = $false)]
[string]$WindowsLang = 'en-us',
[Parameter(Mandatory = $false)]
[ValidateSet('consumer', 'business')]
[string]$MediaType = 'consumer',
[ValidateSet(512, 4096)]
[uint32]$LogicalSectorSizeBytes = 512,
[bool]$Optimize = $true,
[Parameter(Mandatory = $false)]
[ValidateScript({
if ($ -and (!(Test-Path -Path '.\Drivers') -or ((Get-ChildItem -Path '.\Drivers' -Recurse | Measure-Object -Property Length -Sum).Sum -lt 1MB))) {
throw 'CopyDrivers is set to $true, but either the Drivers folder is missing or empty'
}
return $true
})]
[bool]$CopyDrivers,
[bool]$CopyPEDrivers,
[bool]$RemoveFFU,
[bool]$UpdateLatestCU,
[bool]$UpdateLatestNet,
[bool]$UpdateLatestDefender,
[bool]$UpdateEdge,
[bool]$UpdateOneDrive,
[bool]$CopyPPKG,
[bool]$CopyUnattend,
[bool]$CopyAutopilot,
[bool]$CompactOS = $true,
[bool]$CleanupCaptureISO = $true,
[bool]$CleanupDeployISO = $true,
[bool]$CleanupAppsISO = $true
)
$version = '2405.1'
#Check if Hyper-V feature is installed (requires only checks the module)
$osInfo = Get-WmiObject -Class Win32_OperatingSystem
$isServer = $osInfo.Caption -match 'server'
if ($isServer) {
$hyperVFeature = Get-WindowsFeature -Name Hyper-V
if ($hyperVFeature.InstallState -ne "Installed") {
Write-Host "Hyper-V feature is not installed. Please install it before running this script."
exit
}
}
else {
$hyperVFeature = Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-All
if ($hyperVFeature.State -ne "Enabled") {
Write-Host "Hyper-V feature is not enabled. Please enable it before running this script."
exit
}
}
Set default values for variables that depend on other parameters
if (-not $AppsISO) { $AppsISO = "$FFUDevelopmentPath\Apps.iso" }
if (-not $AppsPath) { $AppsPath = "$FFUDevelopmentPath\Apps" }
if (-not $DeployISO) { $DeployISO = "$FFUDevelopmentPath\WinPE_FFU_Deploy.iso" }
if (-not $CaptureISO) { $CaptureISO = "$FFUDevelopmentPath\WinPE_FFU_Capture.iso" }
if (-not $OfficePath) { $OfficePath = "$AppsPath\Office" }
if (-not $rand) { $rand = Get-Random }
if (-not $VMLocation) { $VMLocation = "$FFUDevelopmentPath\VM" }
if (-not $VMName) { $VMName = "$FFUPrefix-$rand" }
if (-not $VMPath) { $VMPath = "$VMLocation$VMName" }
if (-not $VHDXPath) { $VHDXPath = "$VMPath$VMName.vhdx" }
if (-not $FFUCaptureLocation) { $FFUCaptureLocation = "$FFUDevelopmentPath\FFU" }
if (-not $LogFile) { $LogFile = "$FFUDevelopmentPath\FFUDevelopment.log" }
if (-not $KBPath) { $KBPath = "$FFUDevelopmentPath\KB" }
if (-not $DefenderPath) { $DefenderPath = "$AppsPath\Defender" }
if (-not $OneDrivePath) { $OneDrivePath = "$AppsPath\OneDrive" }
if (-not $EdgePath) { $EdgePath = "$AppsPath\Edge" }
#FUNCTIONS
function WriteLog($LogText) {
Add-Content -path $LogFile -value "$((Get-Date).ToString()) $LogText" -Force -ErrorAction SilentlyContinue
Write-Verbose $LogText
}
function LogVariableValues {
$excludedVariables = @(
'PSBoundParameters',
'PSScriptRoot',
'PSCommandPath',
'MyInvocation',
'?',
'ConsoleFileName',
'ExecutionContext',
'false',
'HOME',
'Host',
'hyperVFeature',
'input',
'MaximumAliasCount',
'MaximumDriveCount',
'MaximumErrorCount',
'MaximumFunctionCount',
'MaximumVariableCount',
'null',
'PID',
'PSCmdlet',
'PSCulture',
'PSUICulture',
'PSVersionTable',
'ShellId',
'true'
)
$allVariables = Get-Variable -Scope Script | Where-Object { $_.Name -notin $excludedVariables }
Writelog "Script version: $version"
WriteLog 'Logging variables'
foreach ($variable in $allVariables) {
    $variableName = $variable.Name
    $variableValue = $variable.Value
    if ($null -ne $variableValue) {
        WriteLog "[VAR]$variableName`: $variableValue"
    }
    else {
        WriteLog "[VAR]Variable $variableName not found or not set"
    }
}
WriteLog 'End logging variables'

}
function Invoke-Process {
[CmdletBinding(SupportsShouldProcess)]
param
(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$FilePath,
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string]$ArgumentList
)

$ErrorActionPreference = 'Stop'

try {
    $stdOutTempFile = "$env:TEMP\$((New-Guid).Guid)"
    $stdErrTempFile = "$env:TEMP\$((New-Guid).Guid)"

    $startProcessParams = @{
        FilePath               = $FilePath
        ArgumentList           = $ArgumentList
        RedirectStandardError  = $stdErrTempFile
        RedirectStandardOutput = $stdOutTempFile
        Wait                   = $true;
        PassThru               = $true;
        NoNewWindow            = $true;
    }
    if ($PSCmdlet.ShouldProcess("Process [$($FilePath)]", "Run with args: [$($ArgumentList)]")) {
        $cmd = Start-Process @startProcessParams
        $cmdOutput = Get-Content -Path $stdOutTempFile -Raw
        $cmdError = Get-Content -Path $stdErrTempFile -Raw
        if ($cmd.ExitCode -ne 0) {
            if ($cmdError) {
                throw $cmdError.Trim()
            }
            if ($cmdOutput) {
                throw $cmdOutput.Trim()
            }
        }
        else {
            if ([string]::IsNullOrEmpty($cmdOutput) -eq $false) {
                WriteLog $cmdOutput
            }
        }
    }
}
catch {
    #$PSCmdlet.ThrowTerminatingError($_)
    WriteLog $_
    Write-Host "Script failed - $Logfile for more info"
    throw $_

}
finally {
    Remove-Item -Path $stdOutTempFile, $stdErrTempFile -Force -ErrorAction Ignore

}

}
function Get-ADKURL {
param (
[ValidateSet("Windows ADK", "WinPE add-on")]
[string]$ADKOption
)
# Define base pattern for URL scraping
$basePattern = '<li><a href="(https://[^"]+)" data-linktype="external">Download the '

# Define specific URL patterns based on ADK options
$ADKUrlPattern = @{
    "Windows ADK" = $basePattern + "Windows ADK"
    "WinPE add-on" = $basePattern + "Windows PE add-on for the Windows ADK"
}[$ADKOption]

try {
    # Retrieve content of Microsoft documentation page
    $ADKWebPage = Invoke-RestMethod "https://learn.microsoft.com/en-us/windows-hardware/get-started/adk-install"

    # Extract download URL based on specified pattern
    $ADKMatch = [regex]::Match($ADKWebPage, $ADKUrlPattern)

    if (-not $ADKMatch.Success) {
        WriteLog "Failed to retrieve ADK download URL. Pattern match failed."
        return
    }

    # Extract FWlink from the matched pattern
    $ADKFWLink = $ADKMatch.Groups[1].Value

    if ($null -eq $ADKFWLink) {
        WriteLog "FWLink for $ADKOption not found."
        return
    }

    # Retrieve headers of the FWlink URL
    $FWLinkRequest = Invoke-WebRequest -Uri $ADKFWLink -Method Head -MaximumRedirection 0 -ErrorAction SilentlyContinue

    if ($FWLinkRequest.StatusCode -ne 302) {
        WriteLog "Failed to retrieve ADK download URL. Unexpected status code: $($FWLinkRequest.StatusCode)"
        return
    }

    # Get the ADK link redirected to by the FWlink
    $ADKUrl = $FWLinkRequest.Headers.Location
    return $ADKUrl
}
catch {
    WriteLog $_
    Write-Error "Error occurred while retrieving ADK download URL"
    throw $_
}

}
function Install-ADK {
param (
[ValidateSet("Windows ADK", "WinPE add-on")]
[string]$ADKOption
)
try {
    $ADKUrl = Get-ADKURL -ADKOption $ADKOption

    if ($null -eq $ADKUrl) {
        throw "Failed to retrieve URL for $ADKOption. Please manually install it."
    }

    # Select the installer based on the ADK option specified
    $installer = @{
        "Windows ADK" = "adksetup.exe"
        "WinPE add-on" = "adkwinpesetup.exe"
    }[$ADKOption]

    # Select the feature based on the ADK option specified
    $feature = @{
        "Windows ADK" = "OptionId.DeploymentTools"
        "WinPE add-on" = "OptionId.WindowsPreinstallationEnvironment"
    }[$ADKOption]

    $installerLocation = Join-Path $env:TEMP $installer

    WriteLog "Downloading $ADKOption from $ADKUrl to $installerLocation"
    Start-BitsTransfer -Source $ADKUrl -Destination $installerLocation -ErrorAction Stop
    WriteLog "$ADKOption downloaded to $installerLocation"

    WriteLog "Installing $ADKOption with $feature enabled"
    Invoke-Process $installerLocation "/quiet /installpath ""%ProgramFiles(x86)%\Windows Kits\10"" /features $feature"

    WriteLog "$ADKOption installation completed."
    WriteLog "Removing $installer from $installerLocation"
    # Clean up downloaded installation file
    Remove-Item -Path $installerLocation -Force -ErrorAction SilentlyContinue
}
catch {
    WriteLog $_
    Write-Error "Error occurred while installing $ADKOption. Please manually install it."
    throw $_
}

}
function Get-InstalledProgramRegKey {
param (
[string]$DisplayName
)
$uninstallRegPath = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
$uninstallRegKeys = Get-ChildItem -Path $uninstallRegPath -Recurse

foreach ($regKey in $uninstallRegKeys) {
    try {
        $regValue = $regKey.GetValue("DisplayName")
        if ($regValue -eq $DisplayName) {
            return $regKey
        }
    }
    catch {
        WriteLog $_
        throw "Error retrieving installed program info for $DisplayName : $_"
    }
}

}
function Uninstall-ADK {
param (
[ValidateSet("Windows ADK", "WinPE add-on")]
[string]$ADKOption
)
# Match name as it appears in the registry
$displayName = switch ($ADKOption) {
    "Windows ADK" { "Windows Assessment and Deployment Kit" }
    "WinPE add-on" { "Windows Assessment and Deployment Kit Windows Preinstallation Environment Add-ons" }
}

try {
    $adkRegKey = Get-InstalledProgramRegKey -DisplayName $displayName

    if (-not $adkRegKey) {
        WriteLog "$ADKOption is not installed."
        return
    }

    $adkBundleCachePath = $adkRegKey.GetValue("BundleCachePath")
    WriteLog "Uninstalling $ADKOption..."
    Invoke-Process $adkBundleCachePath "/uninstall /quiet"
    WriteLog "$ADKOption uninstalled successfully."
}
catch {
    WriteLog $_
    Write-Error "Error occurred while uninstalling $ADKOption. Please manually uninstall it."
    throw $_
}

}
function Confirm-ADKVersionIsLatest {
param (
[ValidateSet("Windows ADK", "WinPE add-on")]
[string]$ADKOption
)
$displayName = switch ($ADKOption) {
    "Windows ADK" { "Windows Assessment and Deployment Kit" }
    "WinPE add-on" { "Windows Assessment and Deployment Kit Windows Preinstallation Environment Add-ons" }
}

try {
    $adkRegKey = Get-InstalledProgramRegKey -DisplayName $displayName

    if (-not $adkRegKey) {
        return $false
    }

    $installedADKVersion = $adkRegKey.GetValue("DisplayVersion")

    # Retrieve content of Microsoft documentation page
    $adkWebPage = Invoke-RestMethod "https://learn.microsoft.com/en-us/windows-hardware/get-started/adk-install"
    # Specify regex pattern for ADK version
    $adkVersionPattern = 'ADK\s+(\d+(\.\d+)+)'
    # Check for regex pattern match
    $adkVersionMatch = [regex]::Match($adkWebPage, $adkVersionPattern)

    if (-not $adkVersionMatch.Success) {
        WriteLog "Failed to retrieve latest ADK version from web page."
        return $false
    }

    # Extract ADK version from the matched pattern
    $latestADKVersion = $adkVersionMatch.Groups[1].Value

    if ($installedADKVersion -eq $latestADKVersion) {
        WriteLog "Installed $ADKOption version $installedADKVersion is the latest."
        return $true
    }
    else {
        WriteLog "Installed $ADKOption version $installedADKVersion is not the latest ($latestADKVersion)"
        return $false
    }
}
catch {
    WriteLog "An error occurred while confirming the ADK version: $_"
    return $false
}

}
function Get-ADK {
# Check if latest ADK and WinPE add-on are installed
$latestADKInstalled = Confirm-ADKVersionIsLatest -ADKOption "Windows ADK"
$latestWinPEInstalled = Confirm-ADKVersionIsLatest -ADKOption "WinPE add-on"
# Uninstall older versions and install latest versions if necessary
if (-not $latestADKInstalled) {
    Uninstall-ADK -ADKOption "Windows ADK"
    Install-ADK -ADKOption "Windows ADK"
}

if (-not $latestWinPEInstalled) {
    Uninstall-ADK -ADKOption "WinPE add-on"
    Install-ADK -ADKOption "WinPE add-on"
}

# Define registry path
$adkPathKey = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots"
$adkPathName = "KitsRoot10"

# Check if ADK installation path exists in registry
$adkPathNameExists = (Get-ItemProperty -Path $adkPathKey -Name $adkPathName -ErrorAction SilentlyContinue)

if ($adkPathNameExists) {
    # Get the ADK installation path
    WriteLog 'Get ADK Path'
    $adkPath = (Get-ItemProperty -Path $adkPathKey -Name $adkPathName).$adkPathName
    WriteLog "ADK located at $adkPath"
}
else {
    throw "Windows ADK installation path could not be found."
}

# If ADK was already installed, then check if the Windows Deployment Tools feature is also installed
$deploymentToolsRegKey = Get-InstalledProgramRegKey -DisplayName "Windows Deployment Tools"

if (-not $deploymentToolsRegKey) {
    WriteLog "ADK is installed, but the Windows Deployment Tools feature is not installed."
    $adkRegKey = Get-InstalledProgramRegKey -DisplayName "Windows Assessment and Deployment Kit"
    $adkBundleCachePath = $adkRegKey.GetValue("BundleCachePath")
    if ($adkBundleCachePath) {
        WriteLog "Installing Windows Deployment Tools..."
        $adkInstallPath = $adkPath.TrimEnd('\')
        Invoke-Process $adkBundleCachePath "/quiet /installpath ""$adkInstallPath"" /features OptionId.DeploymentTools"
        WriteLog "Windows Deployment Tools installed successfully."
    }
    else {
        throw "Failed to retrieve path to adksetup.exe to install the Windows Deployment Tools. Please manually install it."
    }
}
return $adkPath

}
function Get-WindowsESD {
param(
[Parameter(Mandatory = $false)]
[ValidateSet(10, 11)]
[int]$WindowsRelease,
    [Parameter(Mandatory = $false)]
    [ValidateSet('x86', 'x64')]
    [string]$WindowsArch,

    [Parameter(Mandatory = $false)]
    [string]$WindowsLang,

    [Parameter(Mandatory = $false)]
    [ValidateSet('consumer', 'business')]
    [string]$MediaType
)
WriteLog "Downloading Windows $WindowsRelease ESD file"
WriteLog "Windows Architecture: $WindowsArch"
WriteLog "Windows Language: $WindowsLang"
WriteLog "Windows Media Type: $MediaType"

# Select cab file URL based on Windows Release
$cabFileUrl = if ($WindowsRelease -eq 10) {
    'https://go.microsoft.com/fwlink/?LinkId=841361'
}
else {
    'https://go.microsoft.com/fwlink/?LinkId=2156292'
}

# Download cab file
WriteLog "Downloading Cab file"
$cabFilePath = Join-Path $PSScriptRoot "tempCabFile.cab"
Invoke-WebRequest -Uri $cabFileUrl -OutFile $cabFilePath
WriteLog "Download succeeded"

# Extract XML from cab file
WriteLog "Extracting Products XML from cab"
$xmlFilePath = Join-Path $PSScriptRoot "products.xml"
Invoke-Process Expand "-F:*.xml $cabFilePath $xmlFilePath"
WriteLog "Products XML extracted"

# Load XML content
[xml]$xmlContent = Get-Content -Path $xmlFilePath

# Define the client type to look for in the FilePath
$clientType = if ($MediaType -eq 'consumer') { 'CLIENTCONSUMER' } else { 'CLIENTBUSINESS' }

# Find FilePath values based on WindowsArch, WindowsLang, and MediaType
foreach ($file in $xmlContent.MCT.Catalogs.Catalog.PublishedMedia.Files.File) {
    if ($file.Architecture -eq $WindowsArch -and $file.LanguageCode -eq $WindowsLang -and $file.FilePath -like "*$clientType*") {
        $esdFilePath = Join-Path $PSScriptRoot (Split-Path $file.FilePath -Leaf)
        #Download if ESD file doesn't already exist
        If (-not (Test-Path $esdFilePath)) {
            #Required to fix slow downloads
            $ProgressPreference = 'SilentlyContinue'
            WriteLog "Downloading $($file.filePath) to $esdFIlePath"
            Invoke-WebRequest -Uri $file.FilePath -OutFile $esdFilePath
            WriteLog "Download succeeded"
            #Set back to show progress
            $ProgressPreference = 'Continue'
            WriteLog "Cleanup cab and xml file"
            Remove-Item -Path $cabFilePath -Force
            Remove-Item -Path $xmlFilePath -Force
            WriteLog "Cleanup done"
        }
        return $esdFilePath
    }
}

}
function Get-ODTURL {
[String]$MSWebPage = Invoke-RestMethod 'https://www.microsoft.com/en-us/download/confirmation.aspx?id=49117'

$MSWebPage | ForEach-Object {
    if ($_ -match 'url=(https://.*officedeploymenttool.*\.exe)') {
        $matches[1]
    }
}

}
function Get-Office {
#Download ODT
$ODTUrl = Get-ODTURL
$ODTInstallFile = "$env:TEMP\odtsetup.exe"
WriteLog "Downloading Office Deployment Toolkit from $ODTUrl to $ODTInstallFile"
Invoke-WebRequest -Uri $ODTUrl -OutFile $ODTInstallFile
# Extract ODT
WriteLog "Extracting ODT to $OfficePath"
# Start-Process -FilePath $ODTInstallFile -ArgumentList "/extract:$OfficePath /quiet" -Wait
Invoke-Process $ODTInstallFile "/extract:$OfficePath /quiet"

# Run setup.exe with config.xml and modify xml file to download to $OfficePath
$ConfigXml = "$OfficePath\DownloadFFU.xml"
$xmlContent = [xml](Get-Content $ConfigXml)
$xmlContent.Configuration.Add.SourcePath = $OfficePath
$xmlContent.Save($ConfigXml)
WriteLog "Downloading M365 Apps/Office to $OfficePath"
# Start-Process -FilePath "$OfficePath\setup.exe" -ArgumentList "/download $ConfigXml" -Wait
Invoke-Process $OfficePath\setup.exe "/download $ConfigXml"

WriteLog "Cleaning up ODT default config files and checking InstallAppsandSysprep.cmd file for proper command line"
#Clean up default configuration files
Remove-Item -Path "$OfficePath\configuration*" -Force

#Read the contents of the InstallAppsandSysprep.cmd file
$content = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"

#Update the InstallAppsandSysprep.cmd file with the Office install command
$officeCommand = "d:\Office\setup.exe /configure d:\Office\DeployFFU.xml"

# Check if Office command is not commented out or missing and fix it if it is
if ($content[2] -ne $officeCommand) {
    $content[2] = $officeCommand

    # Write the modified content back to the file
    Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $content
}

}
function Get-KBLink {
param(
[Parameter(Mandatory)]
[string]$Name
)
$results = Invoke-WebRequest -Uri "http://www.catalog.update.microsoft.com/Search.aspx?q=$Name"
$kbids = $results.InputFields |
Where-Object { $.type -eq 'Button' -and $.Value -eq 'Download' } |
Select-Object -ExpandProperty  ID
Write-Verbose -Message "$kbids"

if (-not $kbids) {
    Write-Warning -Message "No results found for $Name"
    return
}

$guids = $results.Links |
Where-Object ID -match '_link' |
Where-Object { $_.OuterHTML -match ( "(?=.*" + ( $Filter -join ")(?=.*" ) + ")" ) } |
ForEach-Object { $_.id.replace('_link', '') } |
Where-Object { $_ -in $kbids }

if (-not $guids) {
    Write-Warning -Message "No file found for $Name"
    return
}

foreach ($guid in $guids) {
    Write-Verbose -Message "Downloading information for $guid"
    $post = @{ size = 0; updateID = $guid; uidInfo = $guid } | ConvertTo-Json -Compress
    $body = @{ updateIDs = "[$post]" }
    $links = Invoke-WebRequest -Uri 'https://www.catalog.update.microsoft.com/DownloadDialog.aspx' -Method Post -Body $body |
    Select-Object -ExpandProperty Content |
    Select-String -AllMatches -Pattern "http[s]?://[^']*\.microsoft\.com/[^']*|http[s]?://[^']*\.windowsupdate\.com/[^']*" |
    Select-Object -Unique

    foreach ($link in $links) {
        $link.matches.value
        #Filter out cab files
        # #if ($link -notmatch '\.cab') {
        #     $link.matches.value
        # }

    }
}

}
function Get-LatestWindowsKB {
param (
[ValidateSet(10, 11)]
[int]$WindowsRelease
)
# Define the URL of the update history page based on the Windows release
if ($WindowsRelease -eq 11) {
    $updateHistoryUrl = 'https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information'
}
else {
    $updateHistoryUrl = 'https://learn.microsoft.com/en-us/windows/release-health/release-information'
}

# Use Invoke-WebRequest to fetch the content of the page
$response = Invoke-WebRequest -Uri $updateHistoryUrl

# Use a regular expression to find the KB article number
$kbArticleRegex = 'KB\d+'
$kbArticle = [regex]::Match($response.Content, $kbArticleRegex).Value

return $kbArticle

}
function Save-KB {
[CmdletBinding()]
param(
[string[]]$Name,
[string]$Path
)
if ($WindowsArch -eq 'x64') {
    [array]$WindowsArch = @("x64", "amd64")
}

foreach ($kb in $name) {
    $links = Get-KBLink -Name $kb
    foreach ($link in $links) {
        #Check if $WindowsArch is an array
        if ($WindowsArch -is [array]) {
            #Some file names include either x64 or amd64
            if ($link -match $WindowsArch[0] -or $link -match $WindowsArch[1]) {
                Start-BitsTransfer -Source $link -Destination $Path
                $fileName = ($link -split '/')[-1]
                break
            }
            # elseif (!($link -match 'x64' -or $link -match 'amd64' -or $link -match 'x86' -or $link -match 'arm64')) {
            #     Write-Host "No architecture found in $link, assume it's for all architectures"
            #     Start-BitsTransfer -Source $link -Destination $Path
            #     $fileName = ($link -split '/')[-1]
            #     break
            # }
            elseif (!($link -match 'x64' -or $link -match 'amd64' -or $link -match 'x86' -or $link -match 'arm64')) {
                WriteLog "No architecture found in $link, assume this is for all architectures"
                #FIX: 3/22/2024 - the SecurityHealthSetup fix was updated and now includes two files (one is x64 and the other is arm64)
                #Unfortunately there is no easy way to determine the architecture from the file name
                #There is a support doc that include links to download, but it's out of date (n-1)
                #https://support.microsoft.com/en-us/topic/windows-security-update-a6ac7d2e-b1bf-44c0-a028-41720a242da3
                #These files don't change that often, so will check the link above to see when it updates and may use that
                #For now this is hard-coded for these specific file names
                if ($link -match 'security'){
                    #Make sure we're getting the correct architecture for the Security Health Setup update
                    if ($WindowsArch -eq 'x64'){
                        if ($link -match 'securityhealthsetup_e1'){
                            Start-BitsTransfer -Source $link -Destination $Path
                            $fileName = ($link -split '/')[-1]
                            break
                        }
                    }
                    elseif ($WindowsArch -eq 'arm64'){
                        if ($link -match 'securityhealthsetup_25'){
                            Start-BitsTransfer -Source $link -Destination $Path
                            $fileName = ($link -split '/')[-1]
                            break
                        }
                    }
                    continue
                }
                Start-BitsTransfer -Source $link -Destination $Path
                $fileName = ($link -split '/')[-1]
            }
        }
        else {
            if ($link -match $WindowsArch) {
                Start-BitsTransfer -Source $link -Destination $Path
                $fileName = ($link -split '/')[-1]
                break
            }
        }
    }
}
return $fileName

}
function New-AppsISO {
#Create Apps ISO file
$OSCDIMG = "$adkpath`Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\oscdimg.exe"
#Start-Process -FilePath $OSCDIMG -ArgumentList "-n -m -d $Appspath $AppsISO" -wait
Invoke-Process $OSCDIMG "-n -m -d $Appspath $AppsISO"
#Remove the Office Download and ODT
if ($InstallOffice) {
    $ODTPath = "$AppsPath\Office"
    $OfficeDownloadPath = "$ODTPath\Office"
    WriteLog 'Cleaning up Office and ODT download'
    Remove-Item -Path $OfficeDownloadPath -Recurse -Force
    Remove-Item -Path "$ODTPath\setup.exe"
}

}
function Get-WimFromISO {
#Mount ISO, get Wim file
$mountResult = Mount-DiskImage -ImagePath $isoPath -PassThru
$sourcesFolder = ($mountResult | Get-Volume).DriveLetter + ":\sources"
# Check for install.wim or install.esd
$wimPath = (Get-ChildItem $sourcesFolder\install.* | Where-Object { $_.Name -match "install.wim" }).FullName

if ($wimPath) {
    WriteLog "The path to the install file is: $wimPath"
}
else {
    WriteLog "No install.wim or install.esd file found in: $sourcesFolder"
}

return $wimPath

}
function Get-WimIndex {
param (
[Parameter(Mandatory = $true)]
[string]$WindowsSKU
)
WriteLog "Getting WIM Index for Windows SKU: $WindowsSKU"
If ($ISOPath) {
    $wimindex = switch ($WindowsSKU) {
        'Home' { 1 }
        'Home_N' { 2 }
        'Home_SL' { 3 }
        'EDU' { 4 }
        'EDU_N' { 5 }
        'Pro' { 6 }
        'Pro_N' { 7 }
        'Pro_EDU' { 8 }
        'Pro_Edu_N' { 9 }
        'Pro_WKS' { 10 }
        'Pro_WKS_N' { 11 }
        Default { 6 }
    }
}

Writelog "WIM Index: $wimindex"
return $WimIndex

}
function Get-Index {
param(
[Parameter(Mandatory = $true)]
[string]$WindowsImagePath,
    [Parameter(Mandatory = $true)]
    [string]$WindowsSKU
)

# Get the available indexes using Get-WindowsImage
$imageIndexes = Get-WindowsImage -ImagePath $WindowsImagePath

# Get the ImageName of ImageIndex 1 if an ISO was specified, else use ImageIndex 4 - this is usually Home or Education SKU on ESD MCT media
if($ISOPath){
    $imageIndex = $imageIndexes | Where-Object ImageIndex -eq 1
    $WindowsImage = $imageIndex.ImageName.Substring(0, 10)
}
else{
    $imageIndex = $imageIndexes | Where-Object ImageIndex -eq 4
    $WindowsImage = $imageIndex.ImageName.Substring(0, 10)
}

# Concatenate $WindowsImage and $WindowsSKU (E.g. Windows 11 Pro)
$ImageNameToFind = "$WindowsImage $WindowsSKU"

# Find the ImageName in all of the indexes in the image
$matchingImageIndex = $imageIndexes | Where-Object ImageName -eq $ImageNameToFind

# Return the index that matches exactly
if ($matchingImageIndex) {
    return $matchingImageIndex.ImageIndex
}
else {
    # Look for either the number 10 or 11 in the ImageName
    $relevantImageIndexes = $imageIndexes | Where-Object { ($_.ImageName -like "*10*") -or ($_.ImageName -like "*11*") }

    while ($true) {
        # Present list of ImageNames to the end user if no matching ImageIndex is found
        Write-Host "No matching ImageIndex found for $ImageNameToFind. Please select an ImageName from the list below:"

        $i = 1
        $relevantImageIndexes | ForEach-Object {
            Write-Host "$i. $($_.ImageName)"
            $i++
        }

        # Ask for user input
        $inputValue = Read-Host "Enter the number of the ImageName you want to use"

        # Get selected ImageName based on user input
        $selectedImage = $relevantImageIndexes[$inputValue - 1]

        if ($selectedImage) {
            return $selectedImage.ImageIndex
        }
        else {
            Write-Host "Invalid selection, please try again."
        }
    }
}

}
#Create VHDX
function New-ScratchVhdx {
param(
[Parameter(Mandatory = $true)]
[string]$VhdxPath,
[uint64]$SizeBytes = 30GB,
[uint32]$LogicalSectorSizeBytes,
[switch]$Dynamic,
[Microsoft.PowerShell.Cmdletization.GeneratedTypes.Disk.PartitionStyle]$PartitionStyle = [Microsoft.PowerShell.Cmdletization.GeneratedTypes.Disk.PartitionStyle]::GPT
)
WriteLog "Creating new Scratch VHDX..."

$newVHDX = New-VHD -Path $VhdxPath -SizeBytes $disksize -LogicalSectorSizeBytes $LogicalSectorSizeBytes -Dynamic:($Dynamic.IsPresent)
$toReturn = $newVHDX | Mount-VHD -Passthru | Initialize-Disk -PassThru -PartitionStyle GPT

#Remove auto-created partition so we can create the correct partition layout
remove-partition $toreturn.DiskNumber -PartitionNumber 1 -Confirm:$False

Writelog "Done."
return $toReturn

}
#Add System Partition
function New-SystemPartition {
param(
[Parameter(Mandatory = $true)]
[ciminstance]$VhdxDisk,
[uint64]$SystemPartitionSize = 260MB
)
WriteLog "Creating System partition..."

$sysPartition = $VhdxDisk | New-Partition -DriveLetter 'S' -Size $SystemPartitionSize -GptType "{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}" -IsHidden
$sysPartition | Format-Volume -FileSystem FAT32 -Force -NewFileSystemLabel "System"

WriteLog 'Done.'
return $sysPartition.DriveLetter

}
#Add MSRPartition
function New-MSRPartition {
param(
[Parameter(Mandatory = $true)]
[ciminstance]$VhdxDisk
)
WriteLog "Creating MSR partition..."

# $toReturn = $VhdxDisk | New-Partition -AssignDriveLetter -Size 16MB -GptType "{e3c9e316-0b5c-4db8-817d-f92df00215ae}" -IsHidden | Out-Null
$toReturn = $VhdxDisk | New-Partition -Size 16MB -GptType "{e3c9e316-0b5c-4db8-817d-f92df00215ae}" -IsHidden | Out-Null

WriteLog "Done."

return $toReturn

}
#Add OS Partition
function New-OSPartition {
param(
[Parameter(Mandatory = $true)]
[ciminstance]$VhdxDisk,
[Parameter(Mandatory = $true)]
[string]$WimPath,
[uint32]$WimIndex,
[uint64]$OSPartitionSize = 0
)
WriteLog "Creating OS partition..."

if ($OSPartitionSize -gt 0) {
    $osPartition = $vhdxDisk | New-Partition -DriveLetter 'W' -Size $OSPartitionSize -GptType "{ebd0a0a2-b9e5-4433-87c0-68b6b72699c7}"
}
else {
    $osPartition = $vhdxDisk | New-Partition -DriveLetter 'W' -UseMaximumSize -GptType "{ebd0a0a2-b9e5-4433-87c0-68b6b72699c7}"
}

$osPartition | Format-Volume -FileSystem NTFS -Confirm:$false -Force -NewFileSystemLabel "Windows"
WriteLog 'Done'
Writelog "OS partition at drive $($osPartition.DriveLetter):"

WriteLog "Writing Windows at $WimPath to OS partition at drive $($osPartition.DriveLetter):..."

#Server 2019 is missing the Windows Overlay Filter (wof.sys), likely other Server SKUs are missing it as well. Script will error if trying to use the -compact switch on Server OSes
if ((Get-CimInstance Win32_OperatingSystem).Caption -match "Server") {
    WriteLog (Expand-WindowsImage -ImagePath $WimPath -Index $WimIndex -ApplyPath "$($osPartition.DriveLetter):\")
}
if ($CompactOS) {
    WriteLog '$CompactOS is set to true, using -Compact switch to apply the WIM file to the OS partition.'
    WriteLog (Expand-WindowsImage -ImagePath $WimPath -Index $WimIndex -ApplyPath "$($osPartition.DriveLetter):\" -Compact)
}
else {
    WriteLog (Expand-WindowsImage -ImagePath $WimPath -Index $WimIndex -ApplyPath "$($osPartition.DriveLetter):\")
}

WriteLog 'Done'
return $osPartition

}
#Add Recovery partition
function New-RecoveryPartition {
param(
[Parameter(Mandatory = $true)]
[ciminstance]$VhdxDisk,
[Parameter(Mandatory = $true)]
$OsPartition,
[uint64]$RecoveryPartitionSize = 0,
[ciminstance]$DataPartition
)
WriteLog "Creating empty Recovery partition (to be filled on first boot automatically)..."

$calculatedRecoverySize = 0
$recoveryPartition = $null

if ($RecoveryPartitionSize -gt 0) {
    $calculatedRecoverySize = $RecoveryPartitionSize
}
else {
    $winReWim = Get-ChildItem "$($OsPartition.DriveLetter):\Windows\System32\Recovery\Winre.wim"

    if (($null -ne $winReWim) -and ($winReWim.Count -eq 1)) {
        # Wim size + 100MB is minimum WinRE partition size.
        # NTFS and other partitioning size differences account for about 17MB of space that's unavailable.
        # Adding 32MB as a buffer to ensure there's enough space to account for NTFS file system overhead.
        # Adding 250MB as per recommendations from
        # https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/configure-uefigpt-based-hard-drive-partitions?view=windows-11#recovery-tools-partition
        $calculatedRecoverySize = $winReWim.Length + 250MB + 32MB

        WriteLog "Calculated space needed for recovery in bytes: $calculatedRecoverySize"

        if ($null -ne $DataPartition) {
            $DataPartition | Resize-Partition -Size ($DataPartition.Size - $calculatedRecoverySize)
            WriteLog "Data partition shrunk by $calculatedRecoverySize bytes for Recovery partition."
        }
        else {
            $newOsPartitionSize = [math]::Floor(($OsPartition.Size - $calculatedRecoverySize) / 4096) * 4096
            $OsPartition | Resize-Partition -Size $newOsPartitionSize
            WriteLog "OS partition shrunk by $calculatedRecoverySize bytes for Recovery partition."
        }

        $recoveryPartition = $VhdxDisk | New-Partition -DriveLetter 'R' -UseMaximumSize -GptType "{de94bba4-06d1-4d40-a16a-bfd50179d6ac}" `
        | Format-Volume -FileSystem NTFS -Confirm:$false -Force -NewFileSystemLabel 'Recovery'

        WriteLog "Done. Recovery partition at drive $($recoveryPartition.DriveLetter):"
    }
    else {
        WriteLog "No WinRE.WIM found in the OS partition under \Windows\System32\Recovery."
        WriteLog "Skipping creating the Recovery partition."
        WriteLog "If a Recovery partition is desired, please re-run the script setting the -RecoveryPartitionSize flag as appropriate."
    }
}

return $recoveryPartition

}
#Add boot files
function Add-BootFiles {
param(
[Parameter(Mandatory = $true)]
[string]$OsPartitionDriveLetter,
[Parameter(Mandatory = $true)]
[string]$SystemPartitionDriveLetter,
[string]$FirmwareType = 'UEFI'
)
WriteLog "Adding boot files for `"$($OsPartitionDriveLetter):\Windows`" to System partition `"$($SystemPartitionDriveLetter):`"..."
Invoke-Process bcdboot "$($OsPartitionDriveLetter):\Windows /S $($SystemPartitionDriveLetter): /F $FirmwareType"
WriteLog "Done."

}
function Enable-WindowsFeaturesByName {
param (
[Parameter(Mandatory = $true)]
[string]$FeatureNames,
[Parameter(Mandatory = $true)]
[string]$Source
)
$FeaturesArray = $FeatureNames.Split(';')

# Looping through each feature and enabling it
foreach ($FeatureName in $FeaturesArray) {
    WriteLog "Enabling Windows Optional feature: $FeatureName"
    Enable-WindowsOptionalFeature -Path $WindowsPartition -FeatureName $FeatureName -All -Source $Source | Out-Null
    WriteLog "Done"
}

}
#Dismount VHDX
function Dismount-ScratchVhdx {
param(
[Parameter(Mandatory = $true)]
[string]$VhdxPath
)
if (Test-Path $VhdxPath) {
    WriteLog "Dismounting scratch VHDX..."
    Dismount-VHD -Path $VhdxPath
    WriteLog "Done."
}

}
function New-FFUVM {
#Create new Gen2 VM
$VM = New-VM -Name $VMName -Path $VMPath -MemoryStartupBytes $memory -VHDPath $VHDXPath -Generation 2
Set-VMProcessor -VMName $VMName -Count $processors
#Mount AppsISO
Add-VMDvdDrive -VMName $VMName -Path $AppsISO

#Set Hard Drive as boot device
$VMHardDiskDrive = Get-VMHarddiskdrive -VMName $VMName
Set-VMFirmware -VMName $VMName -FirstBootDevice $VMHardDiskDrive
Set-VM -Name $VMName -AutomaticCheckpointsEnabled $false -StaticMemory

#Configure TPM
New-HgsGuardian -Name $VMName -GenerateCertificates
$owner = get-hgsguardian -Name $VMName
$kp = New-HgsKeyProtector -Owner $owner -AllowUntrustedRoot
Set-VMKeyProtector -VMName $VMName -KeyProtector $kp.RawData
Enable-VMTPM -VMName $VMName

#Connect to VM
WriteLog "Starting vmconnect localhost $VMName"
& vmconnect localhost "$VMName"

#Start VM
Start-VM -Name $VMName

return $VM

}
Function Set-CaptureFFU {
$CaptureFFUScriptPath = "$FFUDevelopmentPath\WinPECaptureFFUFiles\CaptureFFU.ps1"
If (-not (Test-Path -Path $FFUCaptureLocation)) {
    WriteLog "Creating FFU capture location at $FFUCaptureLocation"
    New-Item -Path $FFUCaptureLocation -ItemType Directory -Force
    WriteLog "Successfully created FFU capture location at $FFUCaptureLocation"
}

# Create a standard user
$UserExists = Get-LocalUser -Name $UserName -ErrorAction SilentlyContinue
if (-not $UserExists) {
    WriteLog "Creating FFU_User account as standard user"
    New-LocalUser -Name $UserName -AccountNeverExpires -NoPassword | Out-null
    WriteLog "Successfully created FFU_User account"
}

# Create a random password for the standard user
$Password = New-Guid | Select-Object -ExpandProperty Guid
$SecurePassword = ConvertTo-SecureString -String $Password -AsPlainText -Force
Set-LocalUser -Name $UserName -Password $SecurePassword -PasswordNeverExpires:$true

# Create a share of the $FFUCaptureLocation variable
$ShareExists = Get-SmbShare -Name $ShareName -ErrorAction SilentlyContinue
if (-not $ShareExists) {
    WriteLog "Creating $ShareName and giving access to $UserName"
    New-SmbShare -Name $ShareName -Path $FFUCaptureLocation -FullAccess $UserName | Out-Null
    WriteLog "Share created"
}

# Return the share path in the format of \\<IPAddress>\<ShareName> /user:<UserName> <password>
$SharePath = "\\$VMHostIPAddress\$ShareName /user:$UserName $Password"
$SharePath = "net use W: " + $SharePath

# Update CaptureFFU.ps1 script
if (Test-Path -Path $CaptureFFUScriptPath) {
    $ScriptContent = Get-Content -Path $CaptureFFUScriptPath
    $UpdatedContent = $ScriptContent -replace '(net use).*', ("$SharePath")
    WriteLog 'Updating share command in CaptureFFU.ps1 script with new share information'
    Set-Content -Path $CaptureFFUScriptPath -Value $UpdatedContent
    WriteLog 'Update complete'
}
else {
    throw "CaptureFFU.ps1 script not found at $CaptureFFUScriptPath"
}

}
function New-PEMedia {
param (
[Parameter()]
[bool]$Capture,
[Parameter()]
[bool]$Deploy
)
#Need to use the Demployment and Imaging tools environment to create winPE media
$DandIEnv = "$adkPath`Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat"
$WinPEFFUPath = "$FFUDevelopmentPath\WinPE"
If (Test-path -Path "$WinPEFFUPath") {
    WriteLog "Removing old WinPE path at $WinPEFFUPath"
    Remove-Item -Path "$WinPEFFUPath" -Recurse -Force | out-null
}

WriteLog "Copying WinPE files to $WinPEFFUPath"
& cmd /c """$DandIEnv"" && copype amd64 $WinPEFFUPath" | Out-Null
#Invoke-Process cmd "/c ""$DandIEnv"" && copype amd64 $WinPEFFUPath"
WriteLog 'Files copied successfully'

WriteLog 'Mounting WinPE media to add WinPE optional components'
Mount-WindowsImage -ImagePath "$WinPEFFUPath\media\sources\boot.wim" -Index 1 -Path "$WinPEFFUPath\mount" | Out-Null
WriteLog 'Mounting complete'

$Packages = @(
    "WinPE-WMI.cab",
    "en-us\WinPE-WMI_en-us.cab",
    "WinPE-NetFX.cab",
    "en-us\WinPE-NetFX_en-us.cab",
    "WinPE-Scripting.cab",
    "en-us\WinPE-Scripting_en-us.cab",
    "WinPE-PowerShell.cab",
    "en-us\WinPE-PowerShell_en-us.cab",
    "WinPE-StorageWMI.cab",
    "en-us\WinPE-StorageWMI_en-us.cab",
    "WinPE-DismCmdlets.cab",
    "en-us\WinPE-DismCmdlets_en-us.cab"
)

$PackagePathBase = "$adkPath`Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\"

foreach ($Package in $Packages) {
    $PackagePath = Join-Path $PackagePathBase $Package
    WriteLog "Adding Package $Package"
    Add-WindowsPackage -Path "$WinPEFFUPath\mount" -PackagePath $PackagePath | Out-Null
    WriteLog "Adding package complete"
}
If ($Capture) {
    WriteLog "Copying $FFUDevelopmentPath\WinPECaptureFFUFiles\* to WinPE capture media"
    Copy-Item -Path "$FFUDevelopmentPath\WinPECaptureFFUFiles\*" -Destination "$WinPEFFUPath\mount" -Recurse -Force | out-null
    WriteLog "Copy complete"
    #Remove Bootfix.bin - for BIOS systems, shouldn't be needed, but doesn't hurt to remove for our purposes
    Remove-Item -Path "$WinPEFFUPath\media\boot\bootfix.bin" -Force | Out-null
    $WinPEISOName = 'WinPE_FFU_Capture.iso'
    $Capture = $false
}
If ($Deploy) {
    WriteLog "Copying $FFUDevelopmentPath\WinPEDeployFFUFiles\* to WinPE deploy media"
    Copy-Item -Path "$FFUDevelopmentPath\WinPEDeployFFUFiles\*" -Destination "$WinPEFFUPath\mount" -Recurse -Force | Out-Null
    WriteLog 'Copy complete'
    #If $CopyPEDrivers = $true, add drivers to WinPE media using dism
    if ($CopyPEDrivers) {
        WriteLog "Adding drivers to WinPE media"
        try {
            Add-WindowsDriver -Path "$WinPEFFUPath\Mount" -Driver "$FFUDevelopmentPath\PEDrivers" -Recurse -ErrorAction SilentlyContinue | Out-null
        }
        catch {
            WriteLog 'Some drivers failed to be added to the FFU. This can be expected. Continuing.'
        }
        WriteLog "Adding drivers complete"
    }
    $WinPEISOName = 'WinPE_FFU_Deploy.iso'
    $Deploy = $false
}
WriteLog 'Dismounting WinPE media'
Dismount-WindowsImage -Path "$WinPEFFUPath\mount" -Save | Out-Null
WriteLog 'Dismount complete'
#Make ISO
$OSCDIMGPath = "$adkPath`Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg"
$OSCDIMG = "$OSCDIMGPath\oscdimg.exe"
WriteLog "Creating WinPE ISO at $FFUDevelopmentPath\$WinPEISOName"
# & "$OSCDIMG" -m -o -u2 -udfver102 -bootdata:2`#p0,e,b$OSCDIMGPath\etfsboot.com`#pEF,e,b$OSCDIMGPath\Efisys_noprompt.bin $WinPEFFUPath\media $FFUDevelopmentPath\$WinPEISOName | Out-null
Invoke-Process $OSCDIMG "-m -o -u2 -udfver102 -bootdata:2`#p0,e,b`"$OSCDIMGPath\etfsboot.com`"`#pEF,e,b`"$OSCDIMGPath\Efisys_noprompt.bin`" `"$WinPEFFUPath\media`" `"$FFUDevelopmentPath\$WinPEISOName`""
WriteLog "ISO created successfully"
WriteLog "Cleaning up $WinPEFFUPath"
Remove-Item -Path "$WinPEFFUPath" -Recurse -Force
WriteLog 'Cleanup complete'

}
function Optimize-FFUCaptureDrive {
param (
[string]$VhdxPath
)
try {
WriteLog 'Mounting VHDX for volume optimization'
Mount-VHD -Path $VhdxPath
WriteLog 'Defragmenting Windows partition...'
Optimize-Volume -DriveLetter W -Defrag -NormalPriority -Verbose
WriteLog 'Performing slab consolidation on Windows partition...'
Optimize-Volume -DriveLetter W -SlabConsolidate -NormalPriority -Verbose
WriteLog 'Dismounting VHDX'
Dismount-ScratchVhdx -VhdxPath $VhdxPath
WriteLog 'Mounting VHDX as read-only for optimization'
Mount-VHD -Path $VhdxPath -NoDriveLetter -ReadOnly
WriteLog 'Optimizing VHDX in full mode...'
Optimize-VHD -Path $VhdxPath -Mode Full
WriteLog 'Dismounting VHDX'
Dismount-ScratchVhdx -VhdxPath $VhdxPath
} catch {
throw $_
}
}
function New-FFU {
param (
[Parameter(Mandatory = $false)]
[string]$VMName
)
#If $InstallApps = $true, configure the VM
If ($InstallApps) {
WriteLog 'Creating FFU from VM'
WriteLog "Setting $CaptureISO as first boot device"
$VMDVDDrive = Get-VMDvdDrive -VMName $VMName
Set-VMFirmware -VMName $VMName -FirstBootDevice $VMDVDDrive
Set-VMDvdDrive -VMName $VMName -Path $CaptureISO
$VMSwitch = Get-VMSwitch -name $VMSwitchName
WriteLog "Setting $($VMSwitch.Name) as VMSwitch"
get-vm $VMName | Get-VMNetworkAdapter | Connect-VMNetworkAdapter -SwitchName $VMSwitch.Name
WriteLog "Configuring VM complete"
    #Start VM
    WriteLog "Starting VM"
    Start-VM -Name $VMName

    # Wait for the VM to turn off
    do {
        $FFUVM = Get-VM -Name $VMName
        Start-Sleep -Seconds 5
    } while ($FFUVM.State -ne 'Off')
    WriteLog "VM Shutdown"
    # Check for .ffu files in the FFUDevelopment folder
    WriteLog "Checking for FFU Files"
    $FFUFiles = Get-ChildItem -Path $FFUCaptureL

I don't think you can attach files via email and have them show up in the Github issue. Can you attach the files to the Github issue from the website?

unattend.txt
FFUDevelopment.log
BuildFFUVM.txt
unattend.txt
Fixed. Sent as txt files.

FFUDevelopment.log and unattend.xml look fine.
I see you're using your own ISO - Windows-23H2.iso. Have you tried without providing your own ISO and letting the script download the ISO? If not, can you try that? I'd like to rule out the ISO you're providing.
If you can run the same command without the -ISOPath parameter defined, that will let the script download Windows from the Media Creation Tool (yeah, it's a little older, but I just want to see if the process works).

This time, it's stuck on the Lenovo screen, and a window pops up: "The computer restarted unexpectedly or encountered an unexpected error. Windows installation cannot proceed. To install Windows, click "OK" to restart the computer, and then restart the installation." Restarted and tried again, no avail.
Oddly enough, it created 2 ffu files instead of 1 this time. I didn't change anything except for removing the -ISOpath parameter from the command. When starting up, it asks which ffu I want to use and neither worked.

What model is this? Do you know if the hard disk the device comes with is a UFS disk?
Thanks,
Richard

From: Megaroni @.>
Sent: Thursday, June 20, 2024 10:51:34 AM
To: rbalsleyMSFT/FFU @.>
Cc: Richard Balsley @.>; Comment @.>
Subject: Re: [rbalsleyMSFT/FFU] Installation Issue (Issue #29)
This time, it's stuck on the Lenovo screen, and a window pops up: "The computer restarted unexpectedly or encountered an unexpected error. Windows installation cannot proceed. To install Windows, click "OK" to restart the computer, and then restart the installation." Restarted and tried again, no avail.
Oddly enough, it created 2 ffu files instead of 1 this time. I didn't change anything except for removing the -ISOpath parameter from the command. When starting up, it asks which ffu I want to use and neither worked.
image.png (view on web)https://github.com/rbalsleyMSFT/FFU/assets/173206502/314a1b13-03ea-4806-8ce9-90e63ab77725
—
Reply to this email directly, view it on GitHubhttps://github.com/rbalsleyMSFT/FFU/issues/29#issuecomment-2181228091, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AMYE2BBVEEWG2FBIRWCZIHDZIMJCNAVCNFSM6AAAAABJS27TZWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOBRGIZDQMBZGE.
You are receiving this because you commented.Message ID: @.***>

Is the BIOS configured for UEFI with SecureBoot? Or has it been modified? Looking at this device, it looks like it's about 5 years old or so?

Yes it is. And yes it's a little older. We have several of these actually. I also tried disabling secureboot, which gave me the same error message.

Definitely don't want to disable SecureBoot. That should work. I just wanted to make sure the device was configured for UEFI since that's how the partitioning format is configured.
Have you tried another model? I'm wondering if you see the on multiple devices, or just this one model.

Just tried it on a bit newer model. 300w Yoga Gen 4. Got the exact same error. Very odd.

For the 300w, does it use a UFS drive or SSD? I have a 300w with UFS that I image all the time as a test device.
Thanks,
Richard
From: Megaroni @.>
Sent: Friday, June 21, 2024 10:13 AM
To: rbalsleyMSFT/FFU @.>
Cc: Richard Balsley @.>; Comment @.>
Subject: Re: [rbalsleyMSFT/FFU] Installation Issue (Issue #29)
Just tried it on a bit newer model. 300w Yoga Gen 4. Got the exact same error. Very odd.

Reply to this email directly, view it on GitHubhttps://github.com/rbalsleyMSFT/FFU/issues/29#issuecomment-2183132636, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AMYE2BBUOHBWAMXBVIC2MDTZIRNH5AVCNFSM6AAAAABJS27TZWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOBTGEZTENRTGY.
You are receiving this because you commented.Message ID<EMAIL_ADDRESS>

It has an SSD as well.

Are you modifying the C:\ffudevelopment\Apps\InstallAppsandSysprep.cmd file at all with additional apps or commands? Or are you changing anything in the VM itself?
Thanks,
Richard
From: Megaroni @.>
Sent: Friday, June 21, 2024 10:51 AM
To: rbalsleyMSFT/FFU @.>
Cc: Richard Balsley @.>; Comment @.>
Subject: Re: [rbalsleyMSFT/FFU] Installation Issue (Issue #29)
It has an SSD as well.

Reply to this email directly, view it on GitHubhttps://github.com/rbalsleyMSFT/FFU/issues/29#issuecomment-2183185562, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AMYE2BC2VCILWATJ5FRAK3DZIRRW3AVCNFSM6AAAAABJS27TZWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOBTGE4DKNJWGI.
You are receiving this because you commented.Message ID<EMAIL_ADDRESS>

I'm not changing anything in the VM. I am changing the Sysprep command to download one of our firewall apps though. However, I just tried it with the original file with no changes...same error!

@Megaroni I am wondering if you are experiencing issues when Sysprep generalizes your image. Does Sysprep shut down the VM on its own or are you manually shutting it down?

@zehadialam the first time the VM comes up I have to manually shut it down, but the second time it shuts down on its own.

If you are manually shutting down the first time, then Windows was not successfully sysprepped. That would explain the issue you're having with applying the FFU. When the VM launches the first time, does it have an Internet connection?

@zehadialam Oh, interesting. The first time the VM comes up, it isn't connected to the internet but does the second time. The first time, it would just show "hyper-V" on a black screen. I manually connected it in Hyper-V to the virtual switch I created, and it went to the home screen with this window:

I clicked OK and it shut down on its own. But, still have the same error when trying the FFU on a laptop.

Instead of clicking OK on that window, run this command in an admin command prompt window and wait for it to shut down on its own.
C:\windows\system32\sysprep\sysprep.exe /quiet /generalize /oobe
Let me know if the outcome is any different.

@zehadialam That did the trick! Thank you very much!

Happy to help. Glad it's working for you now.


loads() returns inconsistent types

python -c "import geojson; geojson.loads('{}').is_valid"
AttributeError: 'dict' object has no attribute 'is_valid'
If loads(x) succeeds it returns a geojson.feature.____ object, otherwise it returns the result of json.loads(x).
I recommend it always return a feature object.

Sounds good to me, though we'll need to do a major version bump for this, which is fine


[StreamsbIE] Add extractor for streamsb.com (viewsb.com)

Please follow the guide below

You will be asked some questions, please read them carefully and answer honestly
Put an x into all the boxes [ ] relevant to your pull request (like that [x])
Use Preview tab to see how your pull request will actually look like

Before submitting a pull request make sure you have:

[x] Searched the bugtracker for similar pull requests
[x] Read adding new extractor tutorial
[x] Read youtube-dl coding conventions and adjusted the code to meet them
[x] Covered the code with tests (note that PRs without tests will be REJECTED)
[x] Checked the code with flake8

In order to be accepted and merged into youtube-dl each piece of code must be in public domain or released under Unlicense. Check one of the following options:

[x] I am the original author of this code and I am willing to release it under Unlicense
[ ] I am not the original author of this code but it is in public domain or released under Unlicense (provide reliable evidence)

What is the purpose of your pull request?

[ ] Bug fix
[ ] Improvement
[x] New extractor
[ ] New feature

Description of your pull request and other information
add support for streamsb.com
solves:
(https://github.com/ytdl-org/youtube-dl/issues/30607)

/source50 is dynamic.
It's not fixed.
For example, it will change to /source51 after some days.

I investigated the matter regarding the '/sources50' path and found that it's hardcoded. See (app.min.50.js)
var _0x328958=[ ... '/sour', ... ,'ces50'

However, the application JS file is named 'app.min.50.js', it could be that the number 50 represents the version number in both app and sources. This is highly speculative, but we can try it.
Obviously, with a change in version, the algorithm could also change, and we can't do anything about it.

Looks like you sorted it...


Fix Sphinx invocation using obsolete non-existent modules.

Update README with logos
Bump version
fixes #691

Coverage decreased (-1.08%) to 80.742% when pulling 03c1718a4a808e713505108c48898d2d292023b4 on arcivanov:issue_691 into 2efe9874732391f444a5960cc80dc676718808b6 on pybuilder:master.


Team sync April 12

My talking points:

Accessible Pygments - update default background color
Data tables styles... should they apply to RST tables too
Reboot audit

Based on scipy/numpy - the header needs work on PST as a very fragile component in PST
@smeragoel  to update Scientific Python a11y issue: navbar, details, shortcodes in general, mermaid theme
@gabalafou will revisit focusable code blocks (https://github.com/pydata/pydata-sphinx-theme/pull/1104) and we can then look into contributing to sphinx


How about a "get" filter?

Not sure if there is a better standard way but this is what i am missing:
priorities = [{name:"bla", role:1},{name:"blo",role:2},{name:"bli",role:3}]
{{priorities | filterBy: ['role']:clientSession.role | first | get:'name'}}

without get i get an object and no way to display only the name
i wrote this:
(function() {
  "use strict";
  module.exports = function() {
    return function(input,param) {
        return input[param];
    };
  };

}).call(this);

You can simply do it like this:
{{ (priorities | ... | first).name }}

PTAL on this example
Thanks @Harper04