SAPIEN Powershell Studio – Scaling form contents when resizing


Update: June Blender  kindly reached out to the experts on this and provided the following method.


The anchor property defines that that the specified edge of the object should maintain its position in relation to its parent object on that edge.

This means that an anchor set to

  • None will float proportionally to the parent object
  • Left will maintain the number of pixels between the left side of the object and the left side of the parent object
  • Right will maintain the number of pixels between the right side of the object and the right side of the parent object
  • Top  will maintain the number of pixels between the upper edge of the object and the upper edge of the parent object
  • Bottom  will maintain the number of pixels between the lower edge of the object and the lower edge of the parent object

Continue reading

Advertisements

SysJam Powershell RightClick Tool – Part 7 – Querying 64bit Registry Strings with 32bit Powershell

Suppose you are writing a script that requires a 32 bit powershell window. How can you query 64bit registry keys from this script?

If you are connecting to a remote computer your most obvious and best option is Enter-PSSession or New-PSSession to open a native powershell session on the remote computer.

You also have other options for querying registry strings but we need to be careful

Option 1: Get-Item
Lets first consider using Get-Item directly. Here is a very simple function with no error control (or warranty):

Function Get-RegStringValueByGetItem{
    Param([string]$KeyPath,
            [string]$StringName)
    $objRegKey = Get-ItemProperty $KeyPath -Name $StringName
    Return $objRegKey.($stringName)
}

When running from a 64bit powershell session, this returns as expected:

Get-RegStringValueByGetItem -KeyPath 'HKLM:\software\microsoft\Windows\CurrentVersion' -StringName 'CommonFilesDir'

C:\Program Files\Common Files

Get-RegStringValueByGetItem -KeyPath 'HKLM:\software\Wow6432Node\microsoft\Windows\CurrentVersion' -StringName 'CommonFilesDir'

C:\Program Files (x86)\Common Files

Lets try this from a 32bit powershell session:

Get-RegStringValueByGetItem -KeyPath 'HKLM:\software\microsoft\Windows\CurrentVersion' -StringName 'CommonFilesDir'

C:\Program Files (x86)\Common Files

Get-RegStringValueByGetItem -KeyPath 'HKLM:\software\Wow6432Node\microsoft\Windows\CurrentVersion' -StringName 'CommonFilesDir'

C:\Program Files (x86)\Common Files

So, you can see that when running from a 32bit session we get redirected to the Wow6432Node without warning.

Option 2: Microsoft.Win32.RegistryKey
We know that Powershell has access to the DotNet Classes lets try it through the Microsoft.Win32.RegistryKey class.
You can read more about this class here: https://msdn.microsoft.com/en-us/library/Microsoft.Win32.RegistryKey(v=vs.110).aspx

Function Get-RegStringValueBYMicrosoft.Win32.RegistryKeyCLASS{
    Param([string]$KeyPath,
            [string]$StringName,
            [string]$keyRoot
            )
    Switch($keyRoot){
        'HKLM' {$strKeyRoot = [Microsoft.Win32.RegistryHive]'LocalMachine'}
        'HKCR' {$strKeyRoot = [Microsoft.Win32.RegistryHive]'ClassesRoot'}
        'HKCU' {$strKeyRoot = [Microsoft.Win32.RegistryHive]'CurrentUser'}
        'HKU'  {$strKeyRoot = [Microsoft.Win32.RegistryHive]'Users'}
    }

    $objReg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($strKeyRoot, 'localhost')
    $strKeyPath = $keyPath -replace '\\','\\'
    $objSubKey = $objReg.OpenSubKey($strKeyPath)
    $strValue = $objSubKey.GetValue($StringName)

    Return ($strValue)
}

When running from a 64bit powershell session, this returns as expected:

Get-RegStringValueBYMicrosoft.Win32.RegistryKeyCLASS -KeyPath 'software\microsoft\Windows\CurrentVersion' -StringName 'CommonFilesDir' -keyRoot 'HKLM'

C:\Program Files\Common Files

Get-RegStringValueBYMicrosoft.Win32.RegistryKeyCLASS -KeyPath 'software\Wow6432Node\microsoft\Windows\CurrentVersion' -StringName 'CommonFilesDir' -keyRoot 'HKLM'

C:\Program Files (x86)\Common Files

Lets try this from a 32bit powershell session:

Get-RegStringValueBYMicrosoft.Win32.RegistryKeyCLASS -KeyPath 'software\microsoft\Windows\CurrentVersion' -StringName 'CommonFilesDir' -keyRoot 'HKLM'

C:\Program Files (x86)\Common Files

Get-RegStringValueBYMicrosoft.Win32.RegistryKeyCLASS -KeyPath 'software\microsoft\Windows\CurrentVersion' -StringName 'CommonFilesDir' -keyRoot 'HKLM'

C:\Program Files (x86)\Common Files

So, you can see that once again when running from a 32bit session we get redirected to the Wow6432Node without warning.

Option 3: WbemScripting.SWbemNamedValueSet
This last option may take a little to wrap your head around.

Function Get-RegStringValueBYWbemScripting.SWbemNamedValueSetCOM{
    Param([string]$KeyPath,
            [string]$StringName,
            [string]$keyRoot)

    Switch($keyRoot){
        'HKLM' {$strKeyRoot = '&h80000002'}
        'HKCR' {$strKeyRoot = '&h80000000'}
        'HKCU' {$strKeyRoot = '&h80000001'}
        'HKU'  {$strKeyRoot = '&h80000003'}
    }

    #Use the wbem scripting com object to enumerate the 64 bit standard registry provider
    $objNamedValueSet = New-Object -COM 'WbemScripting.SWbemNamedValueSet'
    $objNamedValueSet.Add('__ProviderArchitecture', 64) | Out-Null
    $objLocator = New-Object -COM 'Wbemscripting.SWbemLocator'
    $objServices = $objLocator.ConnectServer('localhost', 'root\default', '', '', '', '', '', $objNamedValueSet)
    $objStdRegProv = $objServices.Get('StdRegProv')
    $Inparams = ($objStdRegProv.Methods_ | where { $_.name -eq 'GetStringValue' }).InParameters.SpawnInstance_()

    # Add the input parameters
    $regkey = $keyPath -replace '\\','\\'
    ($Inparams.Properties_ | where { $_.name -eq 'Hdefkey' }).Value = $strkeyroot
    ($Inparams.Properties_ | where { $_.name -eq 'Ssubkeyname' }).Value = $regkey
    ($Inparams.Properties_ | where { $_.name -eq 'Svaluename' }).Value = $StringName	

    #Execute the method
    $Outparams = $objStdRegProv.ExecMethod_('GetStringValue', $Inparams, '', $objNamedValueSet)
    Return ($Outparams.Properties_ | where { $_.name -eq 'sValue' }).Value

}

You can read more about this COM object here: https://msdn.microsoft.com/en-us/library/aa390788(v=vs.85).aspx and the underlying StdRegProv here: https://msdn.microsoft.com/en-us/library/aa393664%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

Essentially what we are doing is using the WMI scripting Com object to reference the 64bit Registry provider.

Lets see how this works in a 64 bit session:

Get-RegStringValueBYWbemScripting.SWbemNamedValueSetCOM -KeyPath 'software\microsoft\Windows\CurrentVersion' -StringName 'CommonFilesDir' -keyRoot 'HKLM'

C:\Program Files\Common Files

Get-RegStringValueBYWbemScripting.SWbemNamedValueSetCOM -KeyPath 'software\Wow6432Node\microsoft\Windows\CurrentVersion' -StringName 'CommonFilesDir' -keyRoot 'HKLM'

C:\Program Files (x86)\Common Files

And from a 32bit session:

Get-RegStringValueBYWbemScripting.SWbemNamedValueSetCOM -KeyPath 'software\microsoft\Windows\CurrentVersion' -StringName 'CommonFilesDir' -keyRoot 'HKLM'

C:\Program Files\Common Files

Get-RegStringValueBYWbemScripting.SWbemNamedValueSetCOM -KeyPath 'software\Wow6432Node\microsoft\Windows\CurrentVersion' -StringName 'CommonFilesDir' -keyRoot 'HKLM'

C:\Program Files (x86)\Common Files

Finally!

You can see that we needed to use an intermediate session (the WBEM provider) to query the 64 bit registry from a 32 bit shell. This is also the method I used to get the execution history in the SysJam Powershell Rightclick tool from an SCCM client which you can download at https://github.com/mdedeboer/SysJamRightClickToolForConfigMgr and is usable with any of the methods defined by the StdRegProv class.

SysJam Powershell RightClick Tool – Part 6 – Getting Running ConfigMgr Jobs with Powershell

One of the key functionality improvements I wanted to include in the Sysjam Powershell RightClick tool was realtime running job monitoring. There are few tools that don’t require you to click some type of refresh button to see the running jobs.

Part 1 of providing this functionality is the using powershell jobs combined with a timer object to polling any data on a refresh cycle and updating the form. I have covered this previously here

Part 2 of this is querying WMI for the status of each running jobs…and translating this to english.

This post will concentrate on Part 2

Continue reading

SysJam Powershell RightClick Tool – Part 5 – By-Passing User Logon Requirement for a Program

Most of the time when deploying software I’ll set the program to run only with the user logged off. This is to avoid situations when the user may have an older version of the application open when they receive the advertisement. For testing however, this can be a pain….which is why I included the “ByPass User Logon Requirement (Temporary)” button in the Sysjam Powershell RightClick tool. This button sets the requirement to “None” temporarily within WMI. The next time the system does a Machine Policy refresh this setting gets overwritten.
Continue reading

SysJam Powershell RightClick Tool – Part 4 – Getting Users Logged onto a Remote Computer

This post is a combination of the Get-LoggedOnUser script by Jaap Brasser available on the technet gallery here and my post on powershell jobs available here. I am taking both of these concepts and wrapping it all inside my powershell right click tool for SCCM available at https://github.com/mdedeboer/SysJamRightClickToolForConfigMgr.

As you may know, there is no nice way to check a user’s session information with any out-of-the-box powershell cmdlet. Additionally, you could try query this from the SCCM client via wmi, however you’ll be hard pressed to get this to include disconnected terminal sessions as well as console sessions. At least however there is a command available for this. It is called qwinsta or if you prefer its alias quser or another alias “Query User”. (Note there is also a rwinsta command with its alias “Reset Session”).

If you were to type quser into your powershell console however it just spits out text. No nice objects. So if we were to try something like “quser /server:127.0.0.1 | Select-Object -Property Username” you’d get a whole lot of nothing. We’ll need to parse the output ourselves. Thankfully Jaap Brasser has done much of the work for us! This script block will be run by a separate powershell job, so in order to make sure I get all the data I have added each custom object holding the user session information into a hash table that I can pass back to my powershell job. I could just have easily used an array, so no specific reason here.

Lets take a look:

$sbGetLoggedOnUsers = {
	Param ($CompName)     #CompName predefined
	$HashTableCollection = @{ }  #Hashtable to keep all the user sessions in
	$i = 0
	quser /server:$CompName 2> "" | Select-Object -Skip 1 | ForEach-Object { #Get the user information (ignore any errors), skip the title line, for each line after the first line.....
		$CurrentLine = $_.Trim() -Replace '\s+', ' ' -split '\s'  #get rid of repeating whitespaces and split on whitespaces (gives an array of strings)
		$HashProps = @{      #Pre-define a hashtable of properties
			UserName = $CurrentLine[0] #first string in $Currentline
			ComputerName = $CompName
			SessionName = $null
			ID = $null
			State = $null
			IdleTime = $null
			LogonTime = $null
		}
		If ($CurrentLine[2] -eq 'Disc')  #If the session is disconnected quser gives a different layout than otherwise
		{
			$HashProps.SessionName = $null #since the session is disconnected it doesn't have a name
			$HashProps.ID = $CurrentLine[1] #second string in $Current line
			$HashProps.State = $CurrentLine[2] #third string in $Current line
			$HashProps.IdleTime = $CurrentLine[3] #forth string in $Current line
			$HashProps.LogonTime = $CurrentLine[4..6] -join ' ' #fifth to seventh strings in $current line
		}
		else
		{
			$HashProps.SessionName = $CurrentLine[1] #second string in $Current line
			$HashProps.ID = $CurrentLine[2] #third string in $Current line
			$HashProps.State = $CurrentLine[3] #forth string in $Current line
			$HashProps.IdleTime = $CurrentLine[4] #fifth string in $Current line
			$HashProps.LogonTime = $CurrentLine[5..7] -join ' ' #sixth to eighth strings in $current line
		}
		$UserObject = New-Object -TypeName PSCustomObject -Property $HashProps | Select-Object -Property UserName, ComputerName, SessionName, ID, State, IdleTime, LogonTime #Create a new powershell object holding all the properties defined in the hashtable
		if (!($HashTableCollection.ContainsKey($i)))
		{
			$HashTableCollection.Add($i, $UserObject) #Add the custom object to another hashtable
		}
		$i++ #Next user
	}
	return $HashTableCollection #Return hashtable of all user sessions
}

If you are following along at home, you’ll notice a few differences with my version than Jaap’s (besides the script block and extra hash table).
1. quser /server:$CompName 2> “” | Select-Object -Skip 1 | ForEach-Object {
The 2> “” silently discards any error data. This allows us to be sure of what we are parsing.
2. $HashProps = @{
UserName = $CurrentLine[0]
ComputerName = $CompName
SessionName = $null
ID = $null
State = $null
IdleTime = $null
LogonTime = $null
This pre-defines the hashtable’s keys before it has values which provides more consistency.

After the script block is complete you essentially have something similar to this returned (where PSCustomObject is the custom object holding each user’s session information):

@{
   1=PSCustomObject
   2=PSCustomObject
}

The next function basically triggers the scriptblock and when it completes updates a pre-created datagridview with the following columns: Username, ComputerName, SessionName, ID, State, IdleTime, LogonTime. These columns could be named anything, just so long as they are in this order.

If you want the code for the Add-JobTracker function, see my post on this here

function fnLoggedOnUsers
{
	$statusBar1.Text = "Getting Logged On Users"
	if ($dGUsers.Rows.Count -ne 0)
	{
		$dGUsers.Rows.Clear()
	}
	$strComputer = $tbCompName.Text

	if ($strComputer -and $strComputer -ne "")
	{
		Add-JobTracker -Name (Get-Random) `
					   -JobScript $sbGetLoggedOnUsers `
					   -CompletedScript {
			Param ($Job)
			$HashTableUsers = @{ }
			$HashTableUsers = Receive-Job -Job $Job
			ForEach ($key in $HashTableUsers.keys)
			{
				$dGUsers.Rows.Add($HashTableUsers.Item($key).UserName, $HashTableUsers.Item($key).ComputerName, $HashTableUsers.Item($key).SessionName, $HashTableUsers.Item($key).ID, $HashTableUsers.Item($key).State, $HashTableUsers.Item($key).IdleTime, $HashTableUsers.Item($key).LogonTime)
			}
			$statusBar1.Text = ""
		}`
					   -UpdateScript {
		}`
					   -ArgumentList $strComputer
	}
}

So what is happening here? This is all covered in my previous post, but here is a high-level overview:
1. Update a label with the value: “Getting Logged On Users”
2. Clear the datagridview
3. Get the computer name from a text box
4. If the computer name is something, spawn a new powershell job that runs the script block we created above with the computername passed as a parameter.
5. A timer (defined in blog post part 2) checks each powershell job to see if it is finished.
6. When the job is finished the -CompletedScript {} script block is executed in the original thread. This script block uses the output of the first script block as it’s input. For this reason we can be confident that we are getting a hashtable of custom powershell objects as input. We then add each item from the hashtable to the datagridview.

SysJam Powershell Right Click Tool – Part 3 Doing more than 1 thing at once more – Powershell Runspaces and WMI Eventing

I’ll be the first to admit…this is an advanced concept post.  If you think Powershell is cool and you want to learn some pretty crazy things, keep reading.  This post is based loosely on the Process monitoring tab of the SysJam Right Click tool for Configuration manager available at https://github.com/mdedeboer/SysJamRightClickToolForConfigMgr.  I say loosely because I wasn’t satisfied with how much wmi querying it took to get all the information from the remote computer all the way back to you.  I hope to get the code used here into the right click tool sometime soonish…I’m just not sure when yet. Continue reading

SysJam Powershell Right Click Tool – Part 2 Doing more than 1 thing at once – Powershell Jobs

When you build powershell forms for the first time you will notice that whenever you execute code while your form is open everything appears to freeze. What is happening is that you are utilizing the same powershell thread is used to update your form (including when a user tries to move it/scroll etc…) and to also run your code.

To get around this we have two options. The most straight forward one of the two is a little slower running but much easier to code. This is using Powershell jobs. The second option is much quicker to execute and more flexible….it will also require you learn gymnastics within Powershell. This is using synchronized objects within Powershell runspaces.
Continue reading

SysJam Powershell Right Click Tool – Part 1 Introduction

Late yesterday, I was able to post a copy of the SysJam powershell right click tool for Microsoft System Center Configuration Manager clients on codeplex! You can download it here
Continue reading