Client – HDD-Cleanup

Hello together,

as some of you know i have worked in a 3rd level support desk and we created some scripts to make our daily work easier. Here i want to show you one of these. It is pretty easy written but very effective.

Continue reading

Advertisements

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 – configuration for bigger scripts and simple logging

Hello all

In this post i want to show you how to create a configuration with a XML-file easily.
Lots of configuration parameters can be placed in here so that the end user makes his changes in this XML-file where the impact of modifications can be mitigated. Also it cleans up the source code. By loading all relevant parameters within one file you have to look and store all properties at only one place.

Also you can place complex configuration lists and conditional matrixes in it to load them later on with powershell and filter the outcome.

Some examples:

Loading the XML-file

[xml] $configXml = Get-Content -Path "$PSScriptRoot\Config.xml" -ErrorAction 'Stop'

Yeah – that easy.

Exemplaric structure of a file:

<?xml version="1.0" standalone="yes"?>
<Config>
   <DBConnectionString>Provider = OraOLEDB.Oracle; Data Source = ds ; User Id = USER ; Password = pwuser; OLEDB.NET = True;</DBConnectionString>
   <LogDir>c:\Logs</LogDir>
   <ConfigValue Value1="val1"></ConfigValue>
   <ConditionalMatrix>
     <Parameter Value1="val1" Value2="start" BoolValue="1"></Parameter>
     <Parameter Value1="val1" Value2="end" BoolValue="0"></Parameter>
     <Parameter Value1="val2" Value2="test" BoolValue="1"></Parameter>
     <Parameter Value1="val2" Value2="test" BoolValue="0"></Parameter>
     <Parameter Value1="val3" Value2="prod" BoolValue="1"></Parameter>
     <Parameter Value1="val3" Value2="test" BoolValue="0"></Parameter>
   </ConditionalMatrix>
</Config>

Retrieving the data:

#fetching the data directly
$ConnectionString= $configXML.Config.DBConnectionString
$Value1= $configXML.Config.ConfigValue.Value1

$Value1ByConditionalMatrix= ($configXML.Config.ConditionalMatrix.Parameter  | Where-Object {$_.Value2-eq "test" -and $_.BoolValue-eq "1"}).Value1

Easy isn´t it?! Now you have to load the configuration within the script from a relativ path. This could also be the path where afterwards the loggings could be stored into.

A very simple way for logging is to set gather the logging path from config/relative and write log files with a date in it. So you get an overview for each day.

$LogDir=$configXML.Config.LogDir
$LogFile = "$LogDir\Log" + ((Get-Date).Day) + "_" + ((Get-Date).Month) + "_" + ((Get-Date).Year) + "_" + ((Get-Date).Hour) + "_" + ((Get-Date).Minute) +".log"
(Get-Date).ToString()  + " Something happened $Object" >> $LogFile

This can also be empowered even more if you build a separate function for this. So you can grab executing function, date, user etc. which will be written to a log file.

I hope i could give you some hints of the power with working xml-configuration files and enabling you the view for very simple logging.

~David

PS – remote execution of scripts

In this post i want to show you some ways how to execute remote execution of scripts.

First the complicated way:

connect – set execution policy – copy script, execute, delete – roll back execution policy

$Computername=Name
#"Start Session"
$s = New-PSSession -ComputerName $Computername
#"Enable Script Execution on remote System..."
Invoke-Command -Session $s -scriptblock { Set-executionpolicy unrestricted }
#Copy Script
Copy-Item H:\Skript.ps1 \\$Computername\c$\temp\Skript.ps1
#"Start Script..."
Invoke-Command -Session $s -scriptblock { c:\temp\Skript.ps1 }
#Delete Script
Remove-Item \\$Computername\c$\Skript.ps1
#Disable Script Execution on remote System...
Invoke-Command -Session $s -scriptblock { Set-executionpolicy default }
#End Session
Remove-PSSession $s

Next we use Invoke-Command – the scriptfile is copied and executed within the command itself:

Invoke-Command -computer Computername -FilePath C:\Skript.ps1

Next code connects to a computer NOT using Kerberos. This can become necessary if you want to connect to computers outside your domain:

$Computername=Name

#Not using Kerberos:
cd WSMan:\localhost\Client
Set-Item trustedhosts $Computername -force
Restart-Service winrm
Invoke-Command Computername { #Skript in here#} -authentication negotiate -credential Get-Credential

Have fun with it.

~David