My Technical Notes

Friday, 7 April 2017

PowerShell: Performance of different approaches to `Add-Type` guard


function Get-Performance 
{
    [CmdletBinding()]
    param( [scriptblock]$sb )

    $name = $sb.ToString().Trim();
    
    Write-Verbose "Starting $name..."
    $s = [System.Diagnostics.Stopwatch]::StartNew(); 
    (1..250000) | % $sb; 
    $s.Stop(); 
    $elapsed = $s.Elapsed;
    
    Write-Verbose $elapsed;
    Write-Verbose "...Finished $name";
    
    [pscustomobject]@{
        Name = $name;
        Elapsed = $elapsed
    };
}

# the control function should have some code in there to ensure that we are measuring the different approaches.
function Lock-WorkStation_Control {
    $true | Out-Null
}

function Lock-WorkStation_TypeVariable {
    if ($Script:LockWorkStationTypeVariable -eq $null) {
        $namespace = 'Win32FunctionsTypeVariable'
        $name = 'Win32LockWorkStation'
        
        $signature = @'
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
'@
        $Script:LockWorkStationTypeVariable = Add-Type -Namespace $namespace -Name $name -MemberDefinition $signature -PassThru
    }
    
    $Script:LockWorkStationTypeVariable::LockWorkStation() | Out-Null
}

function Lock-WorkStation_Exception {
    
    try {
        [Win32FunctionsException.Win32LockWorkStation] | Out-Null
    } catch {
        $namespace = 'Win32FunctionsException'
        $name = 'Win32LockWorkStation'
        
        $signature = @'
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
'@
        Add-Type -Namespace $namespace -Name $name -MemberDefinition $signature
    }
    
    [Win32FunctionsException.Win32LockWorkStation]::LockWorkStation() | Out-Null
}

function Lock-WorkStation_Unconditional {
    $namespace = 'Win32FunctionsUnconditional'
    $name = 'Win32LockWorkStation'
    
    $signature = @'
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
'@
        
    $LockWorkStationUnconditional = Add-Type -Namespace $namespace -Name $name -MemberDefinition $signature -PassThru      
    
    $LockWorkStationUnconditional::LockWorkStation() | Out-Null
}

function Lock-WorkStation_Mathias {
    $namespace = 'Win32FunctionsMathias'
    $name = 'Win32LockWorkStation'
        
    if(-not ($LockWorkStationMathias = "$namespace.$name" -as [type])){
        $signature = @'
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
'@

        $LockWorkStationMathias = Add-Type -Namespace $namespace -Name $name -MemberDefinition $signature -PassThru
    }
    
    $LockWorkStationMathias::LockWorkStation() | Out-Null
}

function Lock-WorkStation_Boolean_VariableAccess {
    if (!$Script:LockWorkStationDefinedA) {
        $namespace = 'Win32FunctionsBooleanVAccess'
        $name = 'Win32LockWorkStation'
        
        $signature = @'
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
'@
        $Script:LockWorkStationVar = Add-Type -Namespace $namespace -Name $name -MemberDefinition $signature -PassThru
        $Script:LockWorkStationDefinedA = $true;
    }
    
    $Script:LockWorkStationVar::LockWorkStation() | Out-Null
}

function Lock-WorkStation_Boolean_TypeAccess {
    if (!$Script:LockWorkStationDefinedB) {
        $namespace = 'Win32FunctionsTAccess'
        $name = 'Win32LockWorkStation'
        
        $signature = @'
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
'@
        Add-Type -Namespace $namespace -Name $name -MemberDefinition $signature 
        $Script:LockWorkStationDefinedB = $true;
    }
    
    [Win32FunctionsTAccess.Win32LockWorkStation]::LockWorkStation() | Out-Null
}

$SBs = @(
    { Lock-WorkStation_Control },
    { Lock-WorkStation_Exception },
    # { Lock-WorkStation_Unconditional },
    { Lock-WorkStation_Mathias },
    { Lock-WorkStation_Boolean_VariableAccess },
    { Lock-WorkStation_Boolean_TypeAccess },
    { Lock-WorkStation_TypeVariable }
);

$performances = $SBs | % { try { Get-Performance $_ -Verbose } catch { } }

$performances | sort Elapsed -Descending | Format-Table
Running it once, I found:

Name                                    Elapsed
----                                    -------
Lock-WorkStation_Unconditional          00:01:34.9005335
Lock-WorkStation_Exception              00:00:47.0459598
Lock-WorkStation_Mathias                00:00:38.2524806
Lock-WorkStation_Boolean_TypeAccess     00:00:37.1698860
Lock-WorkStation_Boolean_VariableAccess 00:00:36.9747986
Lock-WorkStation_TypeVariable           00:00:36.8496781
Lock-WorkStation_Control                00:00:24.5562487

No comments: