Back from #MSTechDays 2014

It’s the first time I went to Paris to attend the biggest event organized by Microsoft in France.

This year we had 2 PowerShell heroes, PowerShell MVP Carlo Mancini and Fabien Dibot, who presented 2 sessions exclusively dedicated to PowerShell.

Yes, I said heroes because these two guys had to take holidays to come to Paris and without them there would not have been any talk about PowerShell.

Although the duration of the presentation was limited to only 45 minutes, they did a great job at presenting:

  • Powershell remoting and its techniques
  • 45 tips and tricks for a daily use (100% demo)

Again, I’d like to thank Carlo and Fabien. It was a real pleasure to meet you IRL 😀

Waiting for an IP Address

I received at work a Surface Pro 2 and Windows To Go certified USB sticks. Because of the UEFI requirements and the fact that Surface devices don’t have a built-in ethernet adapter, I changed my mind about how to industrialise the installation of such devices.

As my administrative distribution point is portable and I decided to move it to the USB stick and perform the installation directly from the USB stick without any network.

On the USB distribution point, I’ve got the extracted ISO of Windows 8.1 (Enterprise edition in my case), a custom answer file,… and drivers:

As long with these drivers there are some interesting PDF files to download and at the end of document, one can read:

Good idea 🙂
I wanted to keep it simple and started writing a post-installation script exclusively in PowerShell that first deploys drivers.
Here’s how my post-installation script starts:

#region drivers
$letter = (Get-Disk | ? BusType -eq "USB" | Get-Partition)[0].DriveLetter
Write-Verbose -Message "Starting to install drivers" -Verbose
(Get-ChildItem -Path "$($letter):\DISTRIB\WIN81\DRIVERS_x64" -Directory | 
     Sort LastwriteTime -Descending:$false | 
     select -Last 1
).FullName | ForEach-Object {
     Get-ChildItem -Path $_ -Recurse -Filter *.inf  -Exclude autorun.inf | 
     ForEach-Object -Process {
        '{0}' -f $_.FullName
        & (Get-Command "$($env:SystemRoot)\system32\pnputil.exe") @('/i','/a',"$($_.FullName)")
    }
}
#endregion drivers

After loading the wireless driver, I could start configuring the wireless interface and once on the network I’ll perform the remaining tasks that require network availability: activation, updating,…

Getting on the network is a crucial task. If it fails, all the remaining tasks would also fail.

I wanted to have also an elegant way of detecting when my wireless interface was fully configured and ready to perform online tasks.

I couldn’t use the following old trick as it isn’t robust and it is sequential.

Test-Connection -ComputerName ::1 -Count 10

I chose the .Net eventing path. Here’s how:

#region wireless

$network = New-Object System.Net.NetworkInformation.NetworkChange

Register-ObjectEvent -InputObject $network -EventName NetworkAvailabilityChanged -Action {
    (New-Event -SourceIdentifier "NetworkAvailabilityChanged" -Sender $args[0] –EventArguments $args[1].SourceEventArgs.NewEvent.TargetInstance)
}

# Perform some certificate related tasks
<# ... #>
# Start some services
Get-Service -Name dot3svc | Set-Service -StartupType Automatic
Get-Service -Name eaphost,ndisuio | Start-Service -ErrorAction SilentlyContinue
Start-Service -Name dot3svc
# Import the wireless profile
& (Get-Command "$($env:SystemRoot)\system32\netsh.exe") @("wlan","add","profile","filename=$($letter):\Wi-Fi-Intranet.xml","interface=Wi-Fi","user=all")

Wait-Event -SourceIdentifier NetworkAvailabilityChanged
Get-Event -SourceIdentifier NetworkAvailabilityChanged | Remove-Event

#endregion wireless

Bonus: the .Net Class [System.Net.NetworkInformation.NetworkChange] handles two kind of events:

My VM got paused-critical

As you can see my VM got paused-critical

I also examined the administrative events custom view that confirmed that my C: drive was full.

Get-VM -Name MyVM
Get-Volume -DriveLetter C | ft -AutoSize


Note that fixing the issue will restore the VM from a the paused-critical to a paused state. I had to manually resume it:

Get-VM -Name MyVM | Resume-VM


After fixing the issue, I thought it could be nice to generate this custom XML filter on the fly to mimic what the ‘Administrative Events’ view does in the Event viewer.

Storing a fixed XML here strings of lognames isn’t good idea as it may vary based on the roles and features you have.

To create the shortest list of eventlogs to query, I defined a filter to find only enabled logs, that have records…


$events = Get-WinEvent -ListLog * -Force | Where { 
    $_.LogMode -eq 'Circular' -and 
    $_.isEnabled -and 
    $_.RecordCount -and
    $_.LogName  -match "(^\w+$)|(^\w+\s\w+$)|(^(Microsoft-)?(Windows|\w+)(-|\s)((\w+(-|\s)){0,5}\w+)?(/Admin|-Admin))"
} | 
ForEach-Object -Begin {
    $xml = ([xml]@"
    <QueryList>
      <Query Id="0" Path="Application">
    </Query>
    </QueryList>    
"@)
} -Process { 
    $e = $xml.CreateElement("Select")
    # http://stackoverflow.com/questions/3041489/powershell-how-to-add-xmlelement-to-a-non-root-element
    $e.SetAttribute('Path',$_.LogName)
    $e.set_InnerText("*[System[(Level=1  or Level=2 or Level=3)]]")
    $xml.QueryList.Query.AppendChild($e) | Out-Null
} -End {
    Get-WinEvent -FilterXml $xml
} | Sort -Property timecreated 

# Show the results
$events | Select -Last 20  | ft -AutoSize

Enjoy 😀

ActiveDirectory module fails to update

I’ve recently upgraded a Windows 2008 R2 server that had the Powershell Active Directory module enabled to Windows Server 2012 R2.

When I invoked the Update-Help cmdlet on the newly upgraded server, I’ve got the following message:

update-help : Failed to update Help for the module(s) ‘ActiveDirectory’ with UI culture(s) {en-US} : Access to the path ‘C:\windows\system32\WindowsPowerShell\v1.0\Modules\ActiveDirectory\en-US\Microsoft.ActiveDirectory.Management.dll-help.xml’ is denied.

I’ve first tried to remove the feature but it didn’t help

(NB: I haven’t tried the -Remove parameter to avoid a reboot, I guess… or worse)

As you can see below, there are actually multiple problems:

  1. the Builtin\Administrators group doesn’t have at least a write access to the file
  2. all the NTFS permissions aren’t inherited from the parent folder
  3. the owner of the file and parent folder is NT SERVICE\TrustedInstaller 😦

My fix consisted in giving back the ownership of the xml file to the Builtin\Administrators group and giving it as well the missing Write access.

$File = "C:\windows\system32\WindowsPowerShell\v1.0\Modules\ActiveDirectory\en-US\Microsoft.ActiveDirectory.Management.dll-help.xml"            
takeown /F $File /A            
icacls $File --% /grant  *S-1-5-32-544:(W)

After that, I’ve got the help of the ActiveDirectory udpated successfully 😎