Matthias Güntert
Matthias Güntert

Reputation: 4638

PowerShell: Whats the 'best' way to display variable contents via Write-Debug?

What is the best way to display the contents of the variables if $DebugPreference is set accordingly? I have the Impression there must be a better/shorter/more efficient way to accomplish this... any ideas?

I know there is $MyInvocation.BoundParameters, however I don't know how to properly use it in this context. It returns a hashtable, which is not displayed by Write-Debug.

Clear-Host
$VerbosePreference = "Continue"
$DebugPreference = "Continue"
$WhatIfPreference = $true

$Global:Config = @{ 
                    SearchBase = "OU=SomeOU,DC=ad,DC=contoso,DC=com" 
                    LogFolder = "C:\Temp"
                    LogFile = $($MyInvocation.MyCommand.Name -replace ".ps1", ".txt")
                    LogPath = "$($Global:Config.LogFolder)\$($Global:Config.LogFile)"
                  }

Write-Debug "$($MyInvocation.MyCommand.Name): SearchBase = $($Global:Config.SearchBase)"
Write-Debug "$($MyInvocation.MyCommand.Name): LogFolder = $($Global:Config.LogFolder)"
Write-Debug "$($MyInvocation.MyCommand.Name): LogFile = $($Global:Config.LogFile)"
Write-Debug "$($MyInvocation.MyCommand.Name): LogPath = $($Global:Config.LogPath)"

Function Move-MyADObjects
{
    [CmdletBinding()]
    Param(
            [Parameter(Mandatory=$true,HelpMessage="define sitecode e.g. xxxxx")]    
            [string]$Sitz
         )

    $TargetPathUsers = "OU=$sitz,OU=Users,$($Global:Config.SearchBase)"
    $TargetPathGroups = "OU=$sitz,OU=Groups,$($Global:Config.SearchBase)"
    $TargetPathServers = "OU=$sitz,OU=Servers,$($Global:Config.SearchBase)"
    $TargetPathClients = "OU=$sitz,OU=Clients,$($Global:Config.SearchBase)"

    Write-Debug "$($MyInvocation.MyCommand.Name): Sitz = $sitz"
    Write-Debug "$($MyInvocation.MyCommand.Name): TargetPathUsers = $TargetPathUsers"
    Write-Debug "$($MyInvocation.MyCommand.Name): TargetPathGroups = $TargetPathUsers"
    Write-Debug "$($MyInvocation.MyCommand.Name): TargetPathServers = $TargetPathUsers"
    Write-Debug "$($MyInvocation.MyCommand.Name): TargetPathClients = $TargetPathUsers"

    Write-Verbose "Working on $sitz" 

    $filter = "*$sitz*"
    Write-Debug "$($MyInvocation.MyCommand.Name): filter = $filter"

    $BaseOU = (Get-ADOrganizationalUnit -Filter {(Name -like $filter)} -SearchBase $Global:Config.SearchBase -SearchScope 1).DistinguishedName

    Write-Debug "$($MyInvocation.MyCommand.Name): BaseOU = $BaseOU"

    $filter = "2*AB*"
    Write-Debug "$($MyInvocation.MyCommand.Name): filter = $filter"

    $UTuser = Get-ADUser -Filter {(Name -like $filter)} -SearchBase $BaseOU
    Write-Debug "$($MyInvocation.MyCommand.Name): UTuser.Count = $($UTuser.Count)"

    Write-Verbose -Message "Moving ABusers from $sitz to target OU"
    $UTuser | Move-ADObject -TargetPath $TargetPathUsers 
}

Move-MyADObjects -Sitz "12345"

Edit

I am also asking this question because my way of showing variable contents is not very prone to coding errors. If you look at my code above, you may see that I made a mistake. This happend because I had to repeatedly type in var names and started copying and pasting... this leads to confusion when it comes to real debugging. So I guess there must be a better (more automatic) way to do this :-)

Write-Debug "$($MyInvocation.MyCommand.Name): TargetPathUsers = $TargetPathUsers"
Write-Debug "$($MyInvocation.MyCommand.Name): TargetPathGroups = $TargetPathUsers"
Write-Debug "$($MyInvocation.MyCommand.Name): TargetPathServers = $TargetPathUsers"
Write-Debug "$($MyInvocation.MyCommand.Name): TargetPathClients = $TargetPathUsers"

Upvotes: 2

Views: 7618

Answers (1)

beatcracker
beatcracker

Reputation: 6920

"Function: $($MyInvocation.MyCommand.Name)", ($Global:Config | Format-Table -Autosize | Out-String).Trim() | Write-Debug

But how can this be done for simple variables (not hashtables) without having to retype the Name of the variable... The following Shows the Content of the var but not the Name of it... I don't want to manually type/Repeat each var

You can use Get-Variable for that. Here is the function, that will print debug output the way you want.

function Out-Debug
{
    Param
    (
        [System.Management.Automation.InvocationInfo]$Invocation,

        [Parameter(ValueFromPipeline = $true)]
        [string[]]$Variable,

        [string]$Scope = 1
    )

    Process
    {
        foreach($var in $Variable)
        {
            @(
                "Origin: $($Invocation.MyCommand.Name)",
                "Variable: $var",
                'Value:',
                (Get-Variable -Name $var -Scope $Scope -ValueOnly |
                    Format-Table -AutoSize -Wrap | Out-String)
            ) | Write-Debug
        }
    }
}

Usage:

$a = 123
$b = 'qwerty'
$c = @{
    xxx = '111'
    yyy = '222'
}
$Global:d = 'GlobalVar'

Out-Debug -Invocation $MyInvocation -Variable 'a', 'b', 'c'

'a', 'b', 'c' | Out-Debug -Invocation $MyInvocation

Out-Debug -Invocation $MyInvocation -Variable 'd' -Scope 'Global'

Output:

DEBUG: Origin: WriteDebug.ps1
DEBUG: Variable: a
DEBUG: Value:
DEBUG: 123

DEBUG: Origin: WriteDebug.ps1
DEBUG: Variable: b
DEBUG: Value:
DEBUG: qwerty

DEBUG: Origin: WriteDebug.ps1
DEBUG: Variable: c
DEBUG: Value:
DEBUG: 
Name Value
---- -----
yyy  222  
xxx  111  



DEBUG: Origin: WriteDebug.ps1
DEBUG: Variable: a
DEBUG: Value:
DEBUG: 123

DEBUG: Origin: WriteDebug.ps1
DEBUG: Variable: b
DEBUG: Value:
DEBUG: qwerty

DEBUG: Origin: WriteDebug.ps1
DEBUG: Variable: c
DEBUG: Value:
DEBUG: 
Name Value
---- -----
yyy  222  
xxx  111  



DEBUG: Origin: WriteDebug.ps1
DEBUG: Variable: d
DEBUG: Value:
DEBUG: GlobalVar

Upvotes: 5

Related Questions