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

Modifying Permissions on an Active Directory OU with Powershell

There are a few other blogs about this topic, but even so this is not an easy topic to wrap your head around.

To start you off, you’ll want to read:
https://social.technet.microsoft.com/Forums/Lync/en-US/df3bfd33-c070-4a9c-be98-c4da6e591a0a/forum-faq-using-powershell-to-assign-permissions-on-active-directory-objects?forum=winserverpowershell (This is a must read!)
and
http://blogs.technet.com/b/joec/archive/2013/04/25/active-directory-delegation-via-powershell.aspx
Continue reading

Installing DotNet 3.5 on Server 2012 R2 using an offline provisioned image

Consider the following situation:

You have a custom captured wim of Windows Server 2012 R2 that was built before August 2014.
This wim has served you well, but the amount of updates required on servers built by this image means you want to update this image. In this case, you use the offline servicing SCCM feature to update your image.

You also have a task sequence which installs DotNet 3.5 offline, and you are using this task sequence with standalone media.
You use the following command to do this:
Dism /online /enable-feature /featurename:netfx3 /norestart /all /source:D:\Source\sxs
Continue reading

Starting and waiting for an SMA runbook from remote computers

If you are going to manually trigger a SMA runbook from a single computer you’ll want to install the Powershell module from the Orchestrator setup splash screen by clicking on PowerShell administration under Service Management.

However in order to deploy this to a team of administrators we’ll want to automate this. According to the technet library we should be able to use the command:

msiexec.exe /i PowershellModuleInstaller.msi /qn

We can get this PowershellModuleInstaller.msi file from the System Center 2012 R2 Orchestrator 2012 R2 iso in the SMA subfolder.

Continue reading

Using PS Math to check a flag value – Checking Lync RCC without Lync PS Module

I had a unique situation where I didn’t want to deploy the Lync 2013 powershell module to a group of people, but I wanted a way to quickly detect if remote call control (rcc) was enabled for the user. I wasn’t concerned with modifying the setting and simply wanted to read the setting.

I found that the RCC settings for Lync are stored as flags in the AD object. You can view this using ADSI edit and looking for the property “msRTCSIP-OptionFlags”. Then, using this as a reference, we can decode if RCC is configured.

Powershell [math] to the rescue!

In order to tackle this, I needed to know that in behind the scenes the flag is actually calculated using binary. This means that each flag is tied to a power of 2. For example 2^5 = 32. So what we’ll do is find the highest power of two that is less than our flag value of 16. Then we’ll subtract it and do it again. We’ll stop as soon as we’re down to flags totaling less than 32 (1 power of 2 higher than the flag we want). If this number is less than 16, RCC is not enabled. If this number is greater than or equal to 16 RCC is enabled.

First, we’ll need a function to find the highest power of two for a number:

Function Get-HighestPowerOf2{
    #Returns the highest x in 2^x -le $number
    Param(
        [double]$number
    )
    return ([math]::Floor([math]::log($number,2)))
}

Second, we’ll need a function to use the highest power of two and subtract it until we get down to a number less than 32 and check if it is greater than or equal to 16.

Function Get-FlagEnabled{
    Param(
        [double]$Flags,
        [double]$DesiredFlag
    )
    #Get one higher power of two than the flag we want.
    $intOneHigherFlag = [math]::pow(2, (Get-HighestPowerOf2 -number $DesiredFlag) + 1)

    #Remove the sum of all the powers of two higher than the flag we want until the value is less than the flag above the one we want
    Do{
        $Flags = $Flags - ([Math]::pow(2,(Get-HighestPowerOf2 -number $Flags)))
    }While($Flags -ge $intOneHigherFlag) #one power of two higher than 16 (2^5)

    #If the remaining flags are greater than or equal to our desired flag, then our flag is enabled otherwise it is disabled
    If($Flags -ge $DesiredFlag){
        Return $true
    }else{
        Return $false
    }
}

Then test!

#Get the AD user
$objADUser = Get-ADUser -Properties msRTCSIP-OptionFlags -filter {SamAccountName -eq "YourUserName"}

#Get the flags property
$intFlags = [Double]($objADUser | Select-Object -ExpandProperty "msRTCSIP-OptionFlags")

#Is RCC enabled?
Get-FlagEnabled -Flags $intFlags -DesiredFlag 16

Note that this should work for any field that is stored as a flag. You just need to know what flag value you want.

WSUS/SCCM – Tracking Down Updates with Failed Eula Downloads

By running the report “Troubleshooting 1 – Scan errors” you can identify some errors which may be preventing computers in your environment from properly reporting compliance for Windows Updates.

One of the errors you may see in here is -2145124301 which translates to “License terms could not be downloaded”. If there are large numbers of computers reporting this error, you may have an issue with a specific update. 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

Deploying a Java DeploymentRuleSet.Jar using a Active Directory Certificate Services cert

I have seen some discussion about requirements for using a certificate generated from Active Directory Services for signing the DeploymentRuleset.jar file. This post is intended to showcase how I was able to do this…this may or may not be the only way or the best way 🙂

Requirements:
1. The certificate template must have the private key exportable and must be usable for code signing.
2. The certificate chain must be in the trusted root store of the user running JRE in the browser
3. The certificate chain must be verifiable via OCSP responder or revocation list.
4. A Ruleset.xml file … this post doesn’t address creating this file…

Continue reading

HP QTP cannot take screenshots of issues when RDP session is minimized

The issue:
RDP does not paint the screen on the local client if it is minimized or it doesn’t think it has an active console/rdp session. The result is when users run tests in QTP while connecting to a remote machine via RDP and that RDP session is minimized QTP collects blank screenshots.

Steps to Reproduce:
1. User Logs onto computer 1
2. User connects via RDP to machine with QTP. This machine is configured with no screensaver/rdp disconnects. As a result, you can RDP into these and they stay active forever (this allows the users to run long running tests)
3. User runs the HP QTP tests on the machines from step 2.
4. User minimizes the RDP session created in step 2.
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

SMA – Time to Execution Performance

The following TechNet blog post from the Orchestrator team can be used for measuring stress and load performance of your SMA environment: Configure SMA for Optimum Performance

This got me wondering what other ways I could improve performance. I noticed one key area in my scripts was the time while the script was in the “starting” phase. We know that SMA compiles the workflows at run time…so that was my target area.
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