Unknown's avatar

About David das Neves

Hi. My name is David and I work as Premier Field Engineer at Microsoft Germany. My specialties are Dev, Powershell and Windows 10 Client and I am focused in client workshops and dev requests. Beside my work I write my own blog and speak at conferences on PS/Dev topics. Feel free to contact me.

PSGUI – Powershell – RaiseEvent

Hello together

if you want to raise an event by your powershell code use the following command:

$GUI_Manager_rCodeBehind.RaiseEvent((New-Object -TypeName System.Windows.RoutedEventArgs -ArgumentList $([System.Windows.Controls.Button]::ClickEvent)))

The variable (here: $GUI_Manager_rCodeBehind) is the object from which you want to raise the event. In the parameters you have to insert your event in the ArgumentList. This example is for a ButtonClick event – [System.Windows.Controls.Button]::ClickEvent).

May be you will need it at some point.

Greetings,

David

Easy creating Powershell GUI with XAML? PSGUI!

Hello together,

3 months ago i started a project to create user interfaces for Powershell with WPF as simple as possible for everyone by using a  – POWERSHELL GUI.

Powershell GUI with Powershell GUI?! – sounds paradox – but hey – one example will be ready the whole time. 😀

Many times there had been administrators, customers and friends who asked for a GUI in PS. Probably the loudest group crying had been the administrators who normally should work easily with Powershell. But IT-guys are lazy – and because of these laziness we create powerfull scripts which make life easier. And if a wonderfull looking GUI is on top of this functionality – even better!

Though you should never forget – by adding a GUI to a module / function of yours you can prevent lots of input errors by the user. The user gets happy because he can click and sees a wonderful design and you can add an additional abstraction layer preventing lots of headaches.


Aims

The primary aims with this project had been:

  • everyone can do it
  • structured and separated code by logic
  • easy to create and deploy dialogs
  • easy to manage multiple dialogs
  • free code to use for everyone
  • examples for small and easy but also further on more complex solutions
  • preconfigured examples for some use-cases
  • as many internal functions to avoid manual work
  • no dependencies to proprietary programs
PSGUI v0.1

PSGUI v0.1

Interested? then take a look into!

Continue reading

PS files and folder ACLs

Hello all,

i have worked a little bit with ACLs in Powershell and it is a little bit tricky. So i will roundup the code and the most important information for you guys.

This code snippet is a little example how to set the rights for a given folder.

# directory to update
$directory = "C:\Temp\test"
 
# group object 'sAMAccountName' to add to NTFS permission
$addGroup  = "example_access_read"
 
# Configure the access object values - chosen by matrix
$access      = [System.Security.AccessControl.AccessControlType]::Allow 
$rights      = [System.Security.AccessControl.FileSystemRights]"Read,ReadAndExecute,ListDirectory"
$inheritance = [System.Security.AccessControl.InheritanceFlags]"ContainerInherit,ObjectInherit"
$propagation = [System.Security.AccessControl.PropagationFlags]::None 
$ace         = New-Object System.Security.AccessControl.FileSystemAccessRule($addGroup,$rights,$inheritance,$propagation,$access) 
 
# Retrieve the directory ACL and add a new ACL rule
$acl = Get-Acl $directory
$acl.AddAccessRule($ace) 
$acl.SetAccessRuleProtection($false,$false) 
Set-Acl $directory $acl

As you can see we need to define the $access, the $rights and a constellation for $inheritance and $propagation. The first 2 inputs are trivial as you can see. For the last two variables i have made a little table to simplify the conditions. Whether you want different objects (files/folders) or a different depth to be get applied by this rule you have to enter a different constellation for both variables:

ACL2 ACL1

With this information it is quite easy to set and migrate the ACLs of Files/Folders and so on. Hopefully it will help you!

Greetings,

~David

PS – An easy way to log

Hello all,

here i want to show you a nice and elegant method for logging, It´s only one of a various number of possible ways which you can easily extend even more.

Herefore we use a little Powershell trick that overrides the cmdlet. When Powershell tries to resolve this command it will first try to find a function in your code. Here we add our logging methods and invoke the actual function. Sounds hard? nope.

<#          .NOTES          ============================================================================         Created on: 14.02.2016
Created by: David das Neves
Version: 0.2
Project: LogExt
Filename: LogExt.ps1         ============================================================================          .DESCRIPTION  Simple Logging extensions. #> 

#    INPUT
#    ============================================================================
        Set-Variable WriteLogFilePath -Value 'c:\temp\standard.log' -Scope Global
#    ============================================================================

function Out-Default
{
    <# .Synopsis Simple Logging extension. .EXAMPLE Out-Default "logging message" #>
    [cmdletbinding()]
    [AllowEmptyCollection()]
    Param(
        [Parameter(
                   ValueFromPipeline=$true
                   )]
        [string]$Message
    )
    if ($Message)
    {
        $FunctionName = $MyInvocation.MyCommand.Name.ToString()
        Write-WithLog 'Write-Output' $Message
    }
}

function Write-Host
{
    <# .Synopsis Simple Logging extension. .EXAMPLE Write-Host"logging message" #>
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string]$Message
    )
    Write-WithLog $MyInvocation.MyCommand.Name $Message
}

function Write-Output
{
    <# .Synopsis Simple Logging extension. .EXAMPLE Write-Output "logging message" #>
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string]$Message
    )
    Write-WithLog $MyInvocation.MyCommand.Name $Message
}

function Write-Warning
{
    <# .Synopsis Simple Logging extension. .EXAMPLE Write-Warning "logging message" #>
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string]$Message
    )
    Write-WithLog $MyInvocation.MyCommand.Name $Message
}

function Write-Verbose
{
    <# .Synopsis Simple Logging extension. .EXAMPLE Write-Verbose "logging message" #>
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string]$Message
    )
    Write-WithLog $MyInvocation.MyCommand.Name $Message
}

function Write-Debug
{
    <# .Synopsis Simple Logging extension. .EXAMPLE Write-Debug "logging message" #>
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string]$Message
    )
    Write-WithLog $MyInvocation.MyCommand.Name $Message
}

function Write-Error
{
    <# .Synopsis Simple Logging extension. .EXAMPLE Write-Error "logging message" #>
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string]$Message
    )
    Write-WithLog $MyInvocation.MyCommand.Name $Message
}

function Write-WithLog
{
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory=$true)]
        [string]$FunctionName,

        [Parameter(Mandatory=$true)]
        [string]$Message
    )
    if($WriteLogFilePath -and $Message)
    {
        Add-Content -Path $WriteLogFilePath -Value ('{0} [{1}]: {2}' -f `
        (Get-Date -Format G), ($FunctionName.Split('-')[1]), "$Message$newLine")
    }
    Invoke-Expression "Microsoft.PowerShell.Utility\$FunctionName `$Message"
}

With this code you have overwritten all Write-Commands:
– Write-Host
– Write-Output
– Write-Warning
– Write-Verbose
– Write-Debug
– Write-Error
Now you can just type your outputs as by Write-anything and the logging will be done at the same time.

Write-Host a
Write-Output b
Write-Warning c
Write-Verbose d
Write-Debug e
Write-Error f

standardlog

To load the extension you have to import the script – you should also set the logging path. In this example the name of the variable herefore is $WriteLogFilePath.

Complete Loading:

Get-Item 'C:\PS\ExtLog\LogExt.ps1' | Import-Module
$WriteLogFilePath = 'c:\Temp\test2.log'

Have fun with it!

Greetings,

Dave

PS – filtering with many conditions

Hello all.

In many times we have to create more than only one condition to filter the outcome of a result. This produces a lot of unnecessary code and ends up in a bloated code as we can see in this example:

Get-WMIObject Win32_LogicalDisk -filter "DriveType = 3" -ComputerName $computer -ErrorAction SilentlyContinue | 
%{Get-ChildItem ('\\' + $computer + '\' + ($_.DeviceID).remove(1) + '$\*') -File *.doc,*.docx -Recurse -Force -ErrorAction SilentlyContinue | 
?{($_.fullname -notmatch "Windows") -and ($_.fullname -notmatch "Program Files") -and ($_.fullname -notmatch "Program Files (x86)")} |
Add-Content $env:TEMP\$computer.txt

This can be simplified by using Regex. In Regex the pipe “|” means the operation “or”. So we can concat a lot of conditions by using the pipe in the matching string. But be careful. You have to escape every character which is defined in Regex.

This can also be done with the “Escape” function from the Regex class:

[Regex]::Escape($string)

By using this the following code can be compressed

?{($_.fullname -notmatch "Windows") -and ($_.fullname -notmatch "Program Files") -and ($_.fullname -notmatch "Program Files (x86)")}

to this

?{($_.fullname -notmatch "Windows|Program Files|Program Files \(x86\)") 

And more complex esclusions can be added to a hashtable to get an better overview.

$exclusions=@(
"Windows"
"Program Files"
"Program Files (x86)"
)

$exclusions=($exclusions -join "|").Replace('(','\(').Replace(')','\)')

?{($_.fullname -notmatch $exclusions) 

Have fun by using this little trick.

~David

PS – nslookup to serverlist

Hello together,

here i have a simple but nice snippet. This executes a “nslookup” in powershell on a list of computers.

Small but very effective:

$servers = get-content "path_to_the_file"
foreach ($server in $servers) {
$addresses = [System.Net.Dns]::GetHostAddresses($server)
foreach($a in $addresses) {
"{0},{1}" -f $server, $a.IPAddressToString
}}

~David

PS – Get-LastLinesFromFile

Hello together,

sometimes we want to open big files and read the data from it. And by big i mean really big. But many times we also only need some of the last lines – may be the newest ones. Herefore you can use the following script. By this way you do not load the whole file into cache first. This is fast and prevents also upcoming crashes.

<#
.Synopsis
   Gets last Lines of a file.
.EXAMPLE
    Get-LastLinesFromFile -Path "c:\Temp\BigData.csv" -Last 20
#>
function Get-LastLinesFromFile{
param ( $Path, 
      [int]$Last = 10, 
      [int]$ApproxCharsPerLine = 50
) 
    $item = (Get-item $path) 
    if (-not $item) {return} 
    $Stream = $item.Open([System.IO.FileMode]::Open, 
                       [System.IO.FileAccess]::Read, 
                        [System.IO.FileShare]::ReadWrite) 
    $reader = New-Object System.IO.StreamReader($Stream) 

    #Retrieving first set of Lines
    if ($charsPerLine * $last -lt $item.length) {
         $buf=$reader.BaseStream.seek((-1 * $last * $ApproxCharsPerLine) ,[System.IO.SeekOrigin]::End) 
    } 

    $content=$reader.ReadToEnd()
    $LineCount=($content -Split "`n").Count
    $CharsMax = $last * $ApproxCharsPerLine
    $CharsMin = 0

    while ($LineCount -ne $Last)
    {
        if ($LineCount -gt $Last)
        {
            #$content=$reader.ReadToEnd()
            $content=$content -split "`n" -replace "\s+$","" | Select-Object -last $Last
            $LineCount=($content -Split "`n").Count
        
            #obsolete method to near to aiming number
            #new method has better performance
            #$CharsMin =$CharsMin+ ([Math]::Round(($CharsMax-$CharsMin)/2))
            #$reader.BaseStream.seek(-1 * ($CharsMax-$CharsMin),[System.IO.SeekOrigin]::End) 
            #$content=$reader.ReadToEnd()
            #$LineCount=($content -Split "`n").Count
        }
        else
        {
            $CharsMax = $CharsMax+ ([Math]::Round(($CharsMax-$CharsMin)*2))
            $buf=$reader.BaseStream.seek(-1 * ($CharsMax-$CharsMin) ,[System.IO.SeekOrigin]::End) 
            $content=$reader.ReadToEnd()
            $LineCount=($content  -Split "`n").Count
        }
    }

    $Stream.Close() 
    $reader.Close() 

    return $content
}

Have fun with it.

~David