powershell memory requirements in WinPE 4.0

I haven’t seen any information from Microsoft about the amount of memory required to run powershell V3 inside the new WinPE 4.0

The only prerequisites are available on this page and state that:

You must install WinPE-NetFX4, WinPE-Scripting, and WinPE-WMI before you can use WinPE-PowerShell3.

WinPE-PowerShell3 has the following known limitations:

Windows PowerShell remoting is not supported. Any cmdlets that have remoting functionality will return an error.

The Windows PowerShell Integrated Scripting Environment (ISE) is not supported.

Windows PowerShell 2.0 is not supported.

Here are the results of my personal testing and what you can come across:

  • With 512MB

As you can see, Powershell just won’t launch:powershell won't launch

  • With 556MB

It launches but totally fails with an ugly error message: ‘Thread is running or terminated;it cannot restart’. If you only have one command prompt opened, you need to reset the VM, exit, quit, CTRL+C don’t work…
powershell fails with 556MB

  • With 580MB

You can do a $PSVersionTable
Get-Module doesn’t return anything
But Get-module -list doesn’t work and puts the command prompt in a unsuable state (but not unresponsive)

  • Over 582MB

$PSVersionTable works
Get-Module shows modules
Get-module -list shows the list of available modules

Working with DFSR

I’ve recently setup a DFS Namespace on windows 2008 R2 servers and applied all recommended patches that can be found on this page: List of currently available hotfixes for Distributed File System (DFS) technologies in Windows Server 2008 and in Windows Server 2008 R2

I didn’t notice until the following blog post – “Understanding DFSR Dirty (Unexpected) Shutdown Recovery” – but there’s a major change in the recovery method after an unexpected shutdown.

I’ve also had a unexpected shutdown of one of the servers because of a bad power cable 😦

As I’ve applied KB2663685 and already experienced an unexpected shutdown I can troubleshoot if the replication is “broken” but querying the eventlog for event 2213 as indicated.

Get-WinEvent -FilterHashtable @{LogName="DFS Replication";ProviderName="DFSR";Id=2213}            
(Get-WinEvent -FilterHashtable @{LogName="DFS Replication";ProviderName="DFSR";Id=2213})[0].Message

DFSR event ID 2213

The KB article and the blog post also reveals that DFSR related info is stored in the root\MicrosoftDFS namespace.
So to list all the DFSR classes under this namespace and their description, we can do

Get-WmiObject   -Namespace "Root\MicrosoftDFS" -list Dfsr* -Amended | foreach {$_.Name;"="*($_.Name).Length ; $_.Qualifiers | Select-Object Name,Value  | Format-Table Name,Value -Wrap -AutoSize}

DFSR Class description

To restore manually the synchronisation, I prefer using powerwhell rather than the wmic (WMI console) utility.
As I’ve only one object returned when querying the class DfsrVolumeConfig, as I’m using powershell V2 and as the ResumeReplication method doesn’t require any argument (otherwise I’d have used Invoke-WMI cmdlet), I can simply and directly do:

(Get-WmiObject   -Namespace "Root\MicrosoftDFS" -Class DfsrVolumeConfig).ResumeReplication()

Note that once you’ve initiated the manual recovery, the event 2212 is logged to indicate that it has started the recovery. Once completed, you get an event Id 2214.

Get-WinEvent -FilterHashtable @{LogName="DFS Replication";ProviderName="DFSR"} -maxevents 2 | Format-Table Id,Message -Wrap -AutoSize

DFSR manual recovery completed

Tracking user logon activity

Mark Russinovich has presented a screenshot of the autoruns utility during his Malware Hunting with the Sysinternals Tools session at Teched 2012.
He also reported a slowdown issue while he was at Teched 2012 in Europe in the following blog post.

We can actually see more about these scheduled tasks as he posted the following image:
MS tasks Russinovich

These special scheduled tasks remind me the question that Jonathan Walz (‏@jonwalz)
asked on twitter:

Does anyone have a good method for detecting a logon or unlock of a computer (besides the security log (way too chatty)) with WMI?

Well, you may wonder what’s the link between the scheduled tasks from Microsoft on Mark’s laptop and Jonathan’s question ?

I’ve actually been using these kind of scheduled tasks to track user logon activity as the scheduler has now new triggers: Logon,SessionUnlock,RemoteDisconnect,ConsoleConnect,RemoteConnect,SessionLock,RemoteConnect and ConsoleDisconnect

I have been using the following code in quick and dirty mode to create all these local tasks:


Function Get-Template
{
param($trigger)
    $template = @"
    <?xml version="1.0" encoding="UTF-16"?>
    <Task version="1.3" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
      <RegistrationInfo>
        <Date>2011-01-27T17:29:29.0199265</Date>
        <Author>SYSTEM</Author>
      </RegistrationInfo>
    $trigger
      <Principals>
        <Principal id="Author">
          <UserId>S-1-5-18</UserId>
          <RunLevel>HighestAvailable</RunLevel>
        </Principal>
      </Principals>
      <Settings>
        <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
        <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
        <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
        <AllowHardTerminate>true</AllowHardTerminate>
        <StartWhenAvailable>false</StartWhenAvailable>
        <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
        <IdleSettings>
          <StopOnIdleEnd>true</StopOnIdleEnd>
          <RestartOnIdle>false</RestartOnIdle>
        </IdleSettings>
        <AllowStartOnDemand>true</AllowStartOnDemand>
        <Enabled>true</Enabled>
        <Hidden>false</Hidden>
        <RunOnlyIfIdle>false</RunOnlyIfIdle>
        <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
        <UseUnifiedSchedulingEngine>false</UseUnifiedSchedulingEngine>
        <WakeToRun>false</WakeToRun>
        <ExecutionTimeLimit>PT1H</ExecutionTimeLimit>
        <Priority>7</Priority>
      </Settings>
      <Actions Context="Author">
        <Exec>
          <Command>$env:systemroot\System32\WindowsPowerShell\v1.0\powershell.exe</Command>
          <Arguments>-ExecutionPolicy RemoteSigned -File "$env:systemroot\scripts\Get-userinfo.ps1"</Arguments>
        </Exec>
      </Actions>
    </Task>
"@
    return $template
} # end of function

Function Get-SessionTrigger
{
param($trigger)
    $sessiontrigger = @"
      <Triggers>
        <SessionStateChangeTrigger>
          <Enabled>true</Enabled>
            <StateChange>$trigger</StateChange>
        </SessionStateChangeTrigger>
      </Triggers>
"@
    return $sessiontrigger
}

# Handle the logon trigger
$logontrigger = @"
  <Triggers>
    <LogonTrigger>
      <Enabled>true</Enabled>
    </LogonTrigger>
  </Triggers>
"@

# Create the Logon task
$xml = Get-Template -trigger $logontrigger
$xml | Out-File -FilePath ($env:temp +"\tmp.xml") -Encoding Unicode -Force 
Invoke-Expression -Command ("schtasks.exe /create /RU SYSTEM /TN Logon /F /XML " + ($env:temp +"\tmp.xml"))


# Define an array of each connection state
$arraytriggersstate = @(
      "SessionUnlock",
      "RemoteDisconnect",
      "ConsoleConnect",
      "RemoteConnect",
      "SessionLock",
      "RemoteConnect",
      "ConsoleDisconnect"
)

# Loop into the array and create the task
for ($i = 0 ; $i -lt $arraytriggersstate.count ; $i++)
{
    Write-Host -ForegroundColor Green -Object ($arraytriggersstate[$i])
    $xml = Get-Template -trigger  (Get-SessionTrigger -trigger $arraytriggersstate[$i])
    $xml | Out-File -FilePath ($env:temp +"\tmp.xml") -Encoding Unicode -Force 
    Invoke-Expression -Command ("schtasks.exe /create /RU SYSTEM /F /TN " + $arraytriggersstate[$i] + " /XML " + ($env:temp +"\tmp.xml"))
}

The tasks names are important as I’ve been extracting the last tasks names from the new Microsoft-Windows-TaskScheduler/Operational log to know what the user did and writing it to a CSV file that can be read afterward by custom helpdesk tools.

Here is the XML query passed to the Get-WinEvent cmdlet I’ve been using in my Get-userinfo.ps1 script:

  # Wait a little bit until event 129 occurs
 Start-Sleep -Seconds 10
 
 $query =@"
<QueryList>
 <Query Id="0" Path="Microsoft-Windows-TaskScheduler/Operational">
    <Select Path="Microsoft-Windows-TaskScheduler/Operational">*[System[Provider[@Name='Microsoft-Windows-TaskScheduler'] and (Level=4 or Level=0) and ( Task = 129 ) and TimeCreated[timediff(@SystemTime) &lt;=200000 ]]]</Select>
 </Query>
</QueryList>
"@

To know who logged on, I’m using the technique I’ve previously described in the following post Get Logged on users.

As far as I remember, there’s another way to play with logon triggers. It was published as a powershell tip in April on powershell.com and using the Register-ObjectEvent cmdlet and the [Microsoft.Win32.SystemEvents] .net objects.