[Open Source] Opus-NT - An expandable .wim/offline/online installation tweaker

Discussion in 'Application Software' started by Fierelier, Apr 28, 2022.

  1. Fierelier

    Fierelier MDL Novice

    May 16, 2016
    12
    11
    0
    #1 Fierelier, Apr 28, 2022
    Last edited: Jun 22, 2022
  2. Fierelier

    Fierelier MDL Novice

    May 16, 2016
    12
    11
    0
    I've added support for applying the mods to an online installation (see run-online.bat). It's not super-supported and kinda hacked in, but I've had no issues with it until now. It applied successfully to Windows 10 Home 21H2 with tamper protection disabled.
     
  3. AveYo

    AveYo MDL Expert

    Feb 10, 2009
    1,836
    5,685
    60
    Sure there is. RunAsTI.bat
    Being a plain-text hybrid script you can't go more open-source than it.
    And it's also unmatched in utility, since it keeps the environment and the HKCU registry loaded (while all other solutions will have HKCU replaced with the System hive).
    Last but not least, the snippet can easily be incorporated in other cmd or powershell scripts.

    And a dir_own.bat quick implementation (unpolished) to set such permissions in one-go:
    Code:
    @echo off& color 07& title dir_own - lean and mean snippet by AveYo, 2022
    goto :nfo
        [FEATURES]
        - can copy-paste snippet directly in powershell (admin) console then use it manually
        - add -list to show summary even when gui fails; no low-level file functions used
        - can add multiple rules in one go - user and perm number must match, separated by ;      
        [USAGE]
        - First copy-paste dir_own snippet after .bat script content
        - Then call it anywhere (after elevation) to change file security:
          call :dir_own "dir" -recurse yes -user S-1-5-32-545 -owner S-1-1-0 -acc Allow -perm FullControl
    :nfo
    
    :::::::::::::::::::::::::
    :: .bat script content ::
    :::::::::::::::::::::::::
    
    :::: Define TI sid (TrustedInstaller)
    for /f "tokens=3" %%a in ('sc.exe showsid TrustedInstaller') do set TI=%%a >nul
    
    :::: Define USER sid before asking for elevation since it gets replaced for limited accounts
    if "%USER%"=="" for /f "tokens=2" %%u in ('whoami /user /fo list') do (set USER=%%u)
    
    :::: Ask for elevation passing USER and any batch arguments
    fltmc >nul || (set _=set USER=%USER%^& call "%~f0" %*& powershell -nop -c start cmd -args '/d/x/r',$env:_ -verb runas& exit)
    
    set "where=%~dp0TOOLS\Start"
    set "owner=S-1-5-32-544"
    set "users=S-1-5-18;S-1-5-32-544;S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464;S-1-5-32-545"
    set "perms=FullControl;FullControl;FullControl;ReadAndExecute"
    echo;
    call :dir_own "%where%" -recurse yes -owner "%owner%" -user "%users%" -perm "%perms%" -acc Allow -list
    echo;
    
    choice /c EX1T
    exit /b
    
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    :: .bat script content end - copy-paste dir_own snippet ::
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    #:dir_own "Path" -recurse '' -user S-1-5-32-545 -owner '' -acc Allow -perm ReadAndExecute
    set ^ #=&set "0=%~f0"&set 1=%*& powershell -nop -c iex(([io.file]::ReadAllText($env:0)-split'#\:dir_own .*')[1]);# --%% %*&exit/b
    function dir_own { param ( $dir, $recurse='', $user='S-1-5-32-544', $owner='', $acc='Allow', $perm='FullControl', [switch]$list )
     $D1=[uri].module.gettype('System.Diagnostics.Process')."GetM`ember"('SetPrivilege',42)[0]; $s=$user-split';'; $p=$perm-split';'
     'SeSecurityPrivilege','SeTakeOwnershipPrivilege','SeBackupPrivilege','SeRestorePrivilege' |% {$D1.Invoke($null, @("$_",2))}
     $ac='System.Security.AccessControl'; $ds=new-object "$ac.DirectorySecurity"; $fs=new-object "$ac.FileSecurity"
     $s+=($owner,$s[0])[$owner-eq'']; $p+=524288; $n=$s.count; $u=@(0)*$n; $r=@(0)*$n; $h=@(0)*$n; for($i=0;$i -lt $n;$i++){
      $u[$i]=[System.Security.Principal.SecurityIdentifier]$s[$i]; if($i -eq $p.count){break}; $f=@(); 0,3|foreach {
      $f+=new-object System.Security.AccessControl.FileSystemAccessRule($u[$i], $p[$i], $_, 0, 0)}; $r[$i]=$f[0]; $h[$i]=$f[1] }
     function _own($k,$l) { $t=gi -lit $k -force; if($null -eq $t) {return}; try{ $to=$t.GetAccessControl(4); $to.SetOwner($u[-1])
      $t.SetAccessControl($to) }catch {return}; $cp=$t.GetAccessControl(2); $cp.SetAccessRuleProtection($true,$false)
      foreach($ar in $cp.Access) {$cp.RemoveAccessRuleAll($ar)}; foreach($ar in (($r,$h)[$k -eq $dir])) {$cp.AddAccessRule($ar)}
      $t.SetAccessControl($cp); if($re-ne'' -and $t.Root) {$sk=Get-ChildItem $k -Recurse -Force -Attributes !ReparsePoint
      foreach($i in $sk) {_own $i.FullName $false}}; if($l) {$t.FullName; return $t.GetAccessControl()|fl} }; _own $dir $list
    }; iex "dir_own $(([environment]::get_CommandLine()-split'-[-]%+ ?')[1])" #:dir_own lean & mean snippet by AveYo, 2022
    
    
    Have fun!
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  4. Fierelier

    Fierelier MDL Novice

    May 16, 2016
    12
    11
    0
    @AveYo
    RunAsTI.bat looks very interesting, I'll give it a shot! Do you have something similar to do the same as SYSTEM? That'd be useful too. -- And about the permissions, that issue has been resolved with the set-perms.bat and unset-perms.bat scripts I have recently included. It's kinda weird and probably wrong in some way, but it seems to work fine.
     
  5. AveYo

    AveYo MDL Expert

    Feb 10, 2009
    1,836
    5,685
    60
    TI, by all intents and purposes = SYSTEM, with an extra group membership. whoami is still nt authority\system.
    But sure, you can have pure SYSTEM by editing the snippet.Just change:
    Code:
    if (!$TI) {'TrustedInstaller','lsass','winlogon'|% {if (!$As) {$9=sc.exe start $_; $As=@(get-process -name $_ -ea 0|% {$_})[0]}}
    
    to
    Code:
    if (!$TI) {'TrustedInstallerOFF','lsass','winlogon'|% {if (!$As) {$9=sc.exe start $_; $As=@(get-process -name $_ -ea 0|% {$_})[0]}}
    
    so it will not find a service with that name and go to the next, lsass or winlogon, which is System
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  6. Fierelier

    Fierelier MDL Novice

    May 16, 2016
    12
    11
    0
    #6 Fierelier, Jun 24, 2022
    Last edited: Jun 24, 2022
    (OP)
    @AveYo
    Whoa, alright, that's like really amazing. Another thing, is there a way to wait for the script execution to finish? Like if I do RunAsTi.bat cmd.exe, RunAsTi.bat finishes execution before cmd.exe is closed, which is a little prohibiting when scripting. Another thing, I recommend you put setlocal at the top of your script, so no environment variables nor other changes seep out to the parent cmd.exe.

    Edit: On the other hand, running the entire script via RunAsTi.bat could be fine. But I could still see that kind of functionality coming in handy.
     
  7. AveYo

    AveYo MDL Expert

    Feb 10, 2009
    1,836
    5,685
    60
    It actually waits for execution to finish by design, it just hides the background powershell instance to limit confusion.
    And there can't be much environment pollution since admin and then system are barriers by themselves. Plus there's just couple intuitive variables set (0=script name, 1=arguments).
    Running the whole thing as TI is usually preferred, else you're gonna do it repeatedly for each area needing it. No difference than normal running as Admin (who wants 20 UAC prompts?)
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  8. Fierelier

    Fierelier MDL Novice

    May 16, 2016
    12
    11
    0
    #8 Fierelier, Jun 24, 2022
    Last edited: Jun 24, 2022
    (OP)
    @AveYo The background powershell process does wait, but I cannot wait for it when called from a script if that makes sense?
    If I do call RunAsTi.bat cmd.exe, it doesn't wait on the call, it just continues with the next lines even though the powershell process is still open.

    And fair enough about the setlocal.

    Edit: The script doesn't seem to quite parse arguments right:
    call :RunAsTI cmd /k "cd /d %cd% & echo hello world" -- works
    call :RunAsTI cmd /k "cd /d "%cd%" & echo hello world" -- does not work
    I need to put %cd% in quotes, in case the path contains special characters. TrustedInstaller is pain.
     
  9. AveYo

    AveYo MDL Expert

    Feb 10, 2009
    1,836
    5,685
    60
    That's entirely up to you to make manual command-line work.
    Passing quotes around multiple shells is no small feat. You must follow certain rules. There is a whole book dealing with the peculiarities of cmd / powershell / CreateProcess winapi.
    I think I've done quite a nice job simplifying it. Commandline is always gonna be split two ways, first the command (exe), second the arguments, and usually there's just one level of quotes stripping.
    Knowing that, call :RunAsTI cmd "/k cd /d "%cd%" & echo hello world" passes the quotes just fine.
    The outer quotes get stripped and cmd receives what it needs unadulterated.
    You don't even need to guess what it will look like, the exact cmd and args are printed in the UAC prompt itself, just click Show more details.

    As for waiting for execution, that is also not guaranteed in usual scripts if there is some gui-only executable involved or if execution pipe switches from shell to createprocess to etc. and more so when different users, rights and sessions are involved - it's by design. But if you run the whole script as admin / ti / whatever from the get-go, then you can control how it runs better.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  10. Fierelier

    Fierelier MDL Novice

    May 16, 2016
    12
    11
    0
    @AveYo You pointed me in the right direction, I've found a solution and adapted your script. Thank you very much, made stuff way less painful.