Change "Windows font size (DPI)" in PowerShell? - powershell

I'm using a laptop at office (Windows 7) with a station and double screen and at home without station.
The point is I have to change text size each time I switch from station to standlone laptop, because the text size is too big on my double screen, but too small on my laptop screen.
To proceed:
I right-click on desk screen, choose change resolution then "get text and other elements bigger or smaller" to choose 100%, 125%, etc...
I need to restart my session to get the settings applied.
(Note: I'm using a French system, and texts are not exactly the same on us version I suppose).
It's not very convenient so I'd like to automate this, perhaps with a PowerShell script.
Ideally the script may detect if I'm using laptop alone or station with its two screens). Plus, without session restart (I doubt this last point is feasible).
How do I get started? If this is possible.

As supposed in the other answers, the setting under HKLM is not the correct place as the dpi scaling is a user defined setting. The correct registry key is HKCU:\Control Panel\Desktop with the value LogPixels.
More information about all DPI-related registry settings can be found in DPI-related APIs and registry settings.
I wrote a tiny PowerShell script that changes the DPI scaling depending on the current scaling and performs the user logoff, so I just have to execute the script when I put my device to a different monitor.
cd 'HKCU:\Control Panel\Desktop'
$val = Get-ItemProperty -Path . -Name "LogPixels"
if($val.LogPixels -ne 96)
{
Write-Host 'Change to 100% / 96 dpi'
Set-ItemProperty -Path . -Name LogPixels -Value 96
} else {
Write-Host 'Change to 150% / 144 dpi'
Set-ItemProperty -Path . -Name LogPixels -Value 144
}
logoff;exit

Apparently you can set the LogPixels property of
HKLM:/Software/Microsoft/Windows NT/CurrentVersion/FontDPI
which is reiterated in a lot of places around the net. However, I got the impression that dpi was a user setting which makes no sense to have under HKLM.

This is the most straightforward method I've found. I lightly modified the provided function so it's an easy copy/paste. It does not require any registry calls or anything. Simple and very effective.
You can call it like this
Set-Scaling -scaling 0
function Set-Scaling {
# Posted by IanXue-MSFT on
# https://learn.microsoft.com/en-us/answers/questions/197944/batch-file-or-tool-like-powertoy-to-change-the-res.html
# $scaling = 0 : 100% (default)
# $scaling = 1 : 125%
# $scaling = 2 : 150%
# $scaling = 3 : 175%
param($scaling)
$source = #'
[DllImport("user32.dll", EntryPoint = "SystemParametersInfo")]
public static extern bool SystemParametersInfo(
uint uiAction,
uint uiParam,
uint pvParam,
uint fWinIni);
'#
$apicall = Add-Type -MemberDefinition $source -Name WinAPICall -Namespace SystemParamInfo –PassThru
$apicall::SystemParametersInfo(0x009F, $scaling, $null, 1) | Out-Null
}

Sorry, I misread the question. I thought you wanted to control the PowerShell windows.
As already mentioned you could set the LogPixels setting in the registry, to see what the current setting is, try this:
Get-Item -Path Registry::'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontDPI' | Select-Object -ExpandProperty Property
If the LogPixels key is there it will show, you can create it if it does not exist:
Set-Item -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontDPI\LogPixels'
NB: You have to run this with privileges that allow you to manipulate the registry.
There is a good introduction to this over at TechNet.

#Torben Schramme I found that I had to add one more ItemProperty Win8DpiScaling for this work. But, I don't find the "logoff; exit" function working - I still have to do it manually.
cd 'HKCU:\Control Panel\Desktop'
$val = Get-ItemProperty -Path . -Name "LogPixels"
if($val.LogPixels -ne 96)
{
Write-Host 'Change to 100% / 96 dpi'
Set-ItemProperty -Path . -Name LogPixels -Value 96
Set-ItemProperty -Path . -Name Win8DpiScaling 0
} else {
Write-Host 'Change to 150% / 144 dpi'
Set-ItemProperty -Path . -Name LogPixels -Value 144
Set-ItemProperty -Path . -Name Win8DpiScaling 1
}
logoff;exit

After much time, I can't find anything in google.
Well, I made my own script:
$perfis = (Get-ChildItem Registry::HKEY_USERS\ | Where-Object {$_.Name -match "S-1"} | ForEach-Object {Get-ItemProperty "Registry::$_\Control Panel\Desktop" -Name "Win8DpiScaling" -ErrorAction SilentlyContinue}).PSPath
foreach ($_ in $perfis) {Set-ItemProperty -Path "Registry::$_" -Name "Win8DpiScaling" -Value 0}
$monitores = (Get-ChildItem Registry::HKEY_USERS\ | Where-Object {$_.Name -match "S-1"} | ForEach-Object {Get-ChildItem "Registry::$_\Control Panel\Desktop\PerMonitorSettings" -ErrorAction SilentlyContinue}).PSPath
foreach ($_ in $monitores) {Set-ItemProperty -Path "Registry::$_" -Name "DpiValue" -Value 0}

By comparing the output of Get-ItemProperty -Path 'HKCU:\Control Panel\Desktop' before and after using the Windows GUI to set the scaling level, I found the following properties needed setting; worked for me:
cd 'HKCU:\Control Panel\Desktop'
Set-ItemProperty -Path . -Name LogPixels -Value 144
Set-ItemProperty -Path . -Name Win8DpiScaling -Value 1
Set-ItemProperty -Path . -Name FocusBorderHeight -Value 2
Set-ItemProperty -Path . -Name FocusBorderWidth -Value 2
Write-Host 'Sign out and sign back in again to see changes.'

Love this Answer, anyone have any idea on how to set for a single display instead of all at the same time? I have 3 monitors, and this is a universal change.
Set-Scaling -scaling 0
function Set-Scaling {
# Posted by IanXue-MSFT on
# https://learn.microsoft.com/en-us/answers/questions/197944/batch-file-or-tool-like-powertoy-to-change-the-res.html
# $scaling = 0 : 100% (default)
# $scaling = 1 : 125%
# $scaling = 2 : 150%
# $scaling = 3 : 175%
param($scaling)
$source = #'
[DllImport("user32.dll", EntryPoint = "SystemParametersInfo")]
public static extern bool SystemParametersInfo(
uint uiAction,
uint uiParam,
uint pvParam,
uint fWinIni);
'#
$apicall = Add-Type -MemberDefinition $source -Name WinAPICall -Namespace SystemParamInfo –PassThru
$apicall::SystemParametersInfo(0x009F, $scaling, $null, 1) | Out-Null
}

These simple steps worked for me:
Download Win7AndW2K8R2-KB3191566-x64.ZIP from https://learn.microsoft.com/en-us/powershell/wmf/5.1/install-configure
Unzip the file in tmp folder
Open a Powershell command window as Administrator, go in tmp folder where file has been unzipped and execute the following commands :
set-executionpolicy remotesigned
.\Install-WMF5.1.ps1

Related

PowerShell set-itemproperty permission denied

Pls, How i have to solve this problème?
# set disable:
If ($Set_value -eq 0){ (set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\RadioManagement\SystemRadioState").'1'}
Else { (set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\RadioManagement\SystemRadioState").'0'}
# set enable:
If ($Set_value -eq 1){ (set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\RadioManagement\SystemRadioState").'0'}
Else { (set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\RadioManagement\SystemRadioState").'1'}
Thanks for your help
#
There are some problems with your code, starting with the fact that you do have a complete registry path to the registry KEY, but do not supply the entry Name to update.
The second thing is that you need to run it with Admin permissions, since you are trying to alter a registry vaue in the HKEY_LOCAL_MACHINE hive.
You do not say what is in variable $Set_value, but I can imagine this exercise is to toggle the default value in the registry path from 1 to 0 and vice-versa ?
In that case try
$regPath = 'HKLM:\System\CurrentControlSet\Control\RadioManagement\SystemRadioState'
# assuming you obtained the value in this variable like this:
$Set_value = Get-ItemPropertyValue -Path $regPath -Name '(Default)'
# show the current status
$airplaneMode = if ($Set_value) {'Enabled'} else {'Disabled'}
Write-Host "Airplane mode is currently $airplaneMode"
# now toggle it. To make sure the value can only be 1 or 0, I'm using some [math] static methods:
$Set_value = 1 - [math]::Abs([math]::Sign($Set_value)) # 1 --> 0 and 0 --> 1
# and set the new default value
Set-ItemProperty -Path $regPath -Name '(Default)' -Value $Set_value -Type DWord
# show the updated status
$airplaneMode = if ($Set_value) {'Enabled'} else {'Disabled'}
Write-Host "Airplane mode is now $airplaneMode"
Arenas,
Since your $Set_Value can only be 1 or 0 you only need one if test. Also since the value for that item is a Reg_DWORD you want a number as the value not a string.
As to the permission denied you need to run as Administrator. If that doesn't work you need to see your admin to get your access permissions changed.
Edited: As per Theo's post below I added the -Name parameter. I saw a post where it said it was unnecessary for the Default value but obviously that was incorrect!
$RegPath = "HKLM:\System\CurrentControlSet\Control\RadioManagement\SystemRadioState"
If ($Set_value -eq 0 ){ set-ItemProperty -Path "$RegPath" -Name '(Default)' -Value 1 }
Else { set-ItemProperty -Path "$RegPath" -Name '(Default)' -Value 0 }

How can you replace multiple UNC paths of mapped drives via registry using PowerShell?

Our servers team has implemented a DFS, but users across the company still have drives mapped using the server name(s) at various sites. I'd like to push out a PS script that updates a SINGLE registry value (per drive).
My goal is to look through each drive letter key, if the key exists and the remote path starts with the server name then replace it with, the DFS name \\domain.com\SITE\+remainder of the path. This way users keep the same drive letters without having to "remap" their drives
Using Denver office as an example...
$OldServer = "\\denvernas01\"
$NewServer = "\\domain.com\DEN\"
$DriveLetterArray = "A","B","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"
foreach ($DriveLetter in $DriveLetterArray)
{ $Drives = Get-ItemPropertyValue HKCU:\Network\$DriveLetter -Name RemotePath -ErrorAction SilentlyContinue
$RemainingPath = $Drives.Replace($OldServer,"")
foreach ($Drive in $Drives)
{ if ($Drive -like "*$OldServer*")
{ Set-ItemProperty HKCU:\Network\$DriveLetter -Name RemotePath -Value "$NewServer"+"$RemainingPath" }}}
EDIT
^^^This currently works, but only if the server name in RemotePath is all lower case. I.e. the server variables are case sensitive. Any thoughts on how to define the $OldServer & $NewServer variables so it will work with case variations???? e.g. Denvernas01, DENVERNAS01 (or anything inbetween)
I've come across a few threads discussing New-PSDrive, Get-WMIObject, etc, but I'd really like to just replace this one registry value. This would be a good "patch" that would take some stress off of our desktop support team. Trust me - I'll be advocating for GPO to push out common mapped drives once this is all over.
Any feedback is greatly appreciated. Thank you!
If anyone out there is interested, this is what I ended up with, and it worked like a charm. Thought I'd share...
$OldServer = '\\denvernas01'
$NewServer = '\\Domain.com\DEN'
$DriveLetterArray = "A","B","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"
foreach ($DriveLetter in $DriveLetterArray){
$DrivePath = $null; $ConvertedPath = $null
$DrivePath = Get-ItemPropertyValue -Path "HKCU:\Network\$DriveLetter" -Name "RemotePath" -ErrorAction SilentlyContinue
if ($DrivePath -eq $null) {continue}
#Replace Old Drive Path
if ($DrivePath -like "*${OldServer}*") {
$ConvertedPath = $DrivePath -ireplace [regex]::Escape("$Oldserver"), $NewServer
$ConvertedPath
Set-ItemProperty -Path "HKCU:\Network\$DriveLetter" -Name "RemotePath" -Value "${ConvertedPath}"
} else {
#Write-Host "no match"
continue
}
#Write-Host ""
}
#Remove previous mountpoints
Get-ChildItem HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\* | Where-Object Name -Match "##denvernas" | Remove-Item

PowerShell $PROFILE, Variables and NoteProperty / Add-Member

$profile is causing me some headaches. $Profile.GetType() resolves to String which is fine, but it has NoteProperty values:
$profile | Get-Member -Type NoteProperty
AllUsersAllHosts, AllUsersCurrentHost, CurrentUserAllHosts, CurrentUserCurrentHost
When I type $profile, the CurrentUserCurrentHost NoteProperty is returned. This is fine, but I need to change this value - it's complicated, but my corporate VPN uses a network profile and when I am online it tries to reference that location for my $profile meaning that every console startup takes 9 seconds (horribly slow). I can get that down to 1 sec if the profile is loaded locally, but that means changing these values. To do this, I put the following into the AllUsersAllHosts profile.ps1
$profile = C:\Users\($env:Username)\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"
That's fine, but by doing this, I find that all of the NoteProperty values are deleted! So I tried:
$profile.CurrentUserCurrentHost = C:\Users\($env:Username)\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"
But this fails, as the root value of $Profile continues to point at the network profile and Console startup is 9 seconds again!
I then also noticed the following weirdness:
$x = [string]$profile
$x -eq $profile
Ny main questions are:
• Why does $x return True even though $x has none of the NoteProperty values in $profile (as the objects are definitely not the same!)?
• How do I control what the root value of $profile is without destroying the NoteProperty values, and
• How can I update .CurrentUserAllHosts and .CurrentUserCurrentHost in such a way that the root value will also update accordingly? i.e. Even if I do the below, the root value of $profile remains unchanged (still points at the very slow network profile location):
Add-Member -InputObject $PROFILE -NotePropertyName "AllUsersAllHosts" -NotePropertyValue "C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1"
Add-Member -InputObject $PROFILE -NotePropertyName "AllUsersCurrentHost" -NotePropertyValue "C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1"
Add-Member -InputObject $PROFILE -NotePropertyName "CurrentUserAllHosts" -NotePropertyValue "C:\Users\$($env:Username)\Documents\WindowsPowerShell\profile.ps1"
Add-Member -InputObject $PROFILE -NotePropertyName "CurrentUserCurrentHost" -NotePropertyValue "C:\Users\$($env:Username)\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"
While it is technically possible to copy NoteProperty members from one string instance to another (see below), that won't help you, unfortunately:
PowerShell exposes the $PROFILE variable for the user's benefit:
It doesn't use that variable's values internally to determine the profile locations when it loads profiles,
these profile locations are not configurable.
You should treat $PROFILE as a read-only variable, even though it can technically be modified.
For workarounds, see the answer to this related question.
If starting interactive sessions is the focus, the most promising approach is to create a dedicated shortcut file (*.lnk) for launching your PowerShell sessions, defined with a target command such as the following:
powershell -noprofile -noexit -c ". c:\CustomProfileDir\profile.ps1"
To use PowerShell [Core] 6+, substitute pwsh for powershell.
Copying NoteProperty members between objects:
Note:
As stated, this will not solve your problem, but it illustrates how NoteProperty members can be copied from one object to another, even between strings that have different values.
With [string] instances specifically, using -PassThru and assigning back to the input variable ($obj = $obj | Add-Member -PassThru ...) is required in order for the NoteProperty members to be retained; for other types, $obj | Add-Member ... is sufficient.
# Assign the new string value to a new (temporary) variable.
$newProfile = '/path/to/my.ps1'
# Copy the NoteProperty members from the original, decorated string
# to the new variable's string instance.
$PROFILE.psobject.properties | where MemberType -eq 'NoteProperty' | foreach {
$newProfile = $newProfile |
Add-Member -PassThru -NotePropertyName $_.Name -NotePropertyValue $_.Value
}
# You can now assign the new variable to the old one,
# but note that *with $PROFILE that won't help*.
# $PROFILE SHOULD BE TREATED AS READ-ONLY.
$PROFILE = $newProfile
As #mklement0 pointed out, I cannot bypass the functionality of $profile, but I can trick it. Without the below, all shells and scripts take 6.5 to 9 sec to start when I am remotely connected to my corporate VPN (part of that, about 3 seconds is my $profile functions etc). With the below, all consoles and scripts startup in 1 second (and that includes my $profile functions about 1000 lines of code). Putting this solution here in case of help to others.
Running the code at the bottom of this answer results in pushing the following into my $Profile.AllUsersAllHosts which will now always reference a profile at the default C:\ location (and correctly per host type as well - console, ISE, VSCode etc).
Set-Location C:\Users\$($env:Username)
# Prevent loading profile from network share
if ($Profile.CurrentUserCurrentHost -ne "C:\Users\$($env:Username)\Documents\WindowsPowerShell\$(($Profile).split(`"\`")[-1])") {
$Profile = "C:\Users\$($env:Username)\Documents\WindowsPowerShell\$(($Profile).split(`"\`")[-1])"
if (Test-Path "$Profile") { . $Profile }
}
All I then need to do is delete any profiles on the network share and now I get 1 second load times whether connected remotely to the VPN or not, and whether I open a console or a script etc.
Write-Host ""
Write-Host "Do you want to update `$Profile.AllUsersAllHosts to always redirect to C:\Users\$($env:Username) ?"
Write-Host "This can significantly speed up PowerShell load times when working with a network share over a VPN."
Write-Host "Note that this is just a bypass to always use the *default* profile location on C:\."
Write-Host " `$Profile.AllUsersAllHosts = C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1"
Write-Host " `$Profile.CurrentHostCurrentUser = C:\Users\$($env:Username)\Documents\WindowsPowerShell\$(($Profile).split("\"))[-1]_profile.ps1"
Write-Host ""
$ProfileAdmin = "C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1"
# Use (($Profile).split("\"))[-1] to capture correct prefix PowerShell, VSCode. $ShellId does not work for VSCode etc
$ProfileUser = "C:\Users\$($env:Username)\Documents\WindowsPowerShell\$(($Profile).split('\')[-1])"
$ProfileUserText = '"C:\Users\$($env:Username)\Documents\WindowsPowerShell\$(($Profile).split(`"\`")[-1])"'
Write-Host "Press any key to use `$Profile.AllUsersAllHosts to stop using a profile from a network share"
pause
# - Create $Profile.AllUsersAllHosts
# - Set-Location C:\Users\$($env:Username) (override Admin defaulting into system32)
# - If the system decides that it will use C:\ have to check that so that we do not double-load $Profile!
# - If that condition is ok, set $Profile = "C:\Users\$($env:Username)\Documents\WindowsPowerShell\$($ShellId)_profile.ps1"
# - Then just dotsource $Profile as it's set to the C:\ drive as required.
if (!(Test-Path $(Split-Path $ProfileAdmin))) { mkdir $(Split-Path $ProfileAdmin) -Force }
if (!(Test-Path $(Split-Path $ProfileUser))) { mkdir $(Split-Path $ProfileUser) -Force }
Write-Host "`nCreating backup of existing profile ..."
If (Test-Path $ProfileAdmin) { Copy-Item -Path "$($ProfileAdmin)" -Destination "$($ProfileAdmin)_$(Get-Date -format "yyyy-MM-dd__HH-mm-ss").txt" }
Set-Content -Path $ProfileAdmin -Value "Set-Location C:\Users\`$(`$env:Username)"
Add-Content -Path $ProfileAdmin -Value ""
Add-Content -Path $ProfileAdmin -Value "# Prevent loading profile from network share"
Add-Content -Path $ProfileAdmin -Value "if (`$Profile.CurrentUserCurrentHost -ne $ProfileUserText) {"
Add-Content -Path $ProfileAdmin -Value " `$Profile = $ProfileUserText"
Add-Content -Path $ProfileAdmin -Value " if (Test-Path `"`$Profile`") { . `$Profile }"
Add-Content -Path $ProfileAdmin -Value "}"

Creating Key in regedit with "/"in the name

Hi i'm just wondering im currently creating folder on my registry this is my code
function AddMachineRegistry{
param(
[string] $registryPath = $(throw "registryPath is a required parameter"),
[string] $name = $(throw "name is a required parameter"),
[int] $value = $(throw "value is a required parameter")
)
IF(!(Test-Path $registryPath))
{
New-Item -Path $registryPath -ItemType Key -Force | Out-Null
}
New-ItemProperty -Path $registryPath -Name $name -Value $value -PropertyType DWORD -force | Out-Null
}
and tried to used it like this
AddMachineRegistry "HKLM:\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 40/128\" "Enabled" 0
basically im trying to create a key with the name of "RC4 40/128" but when i execute it it creates "RC4 40" folder and under that it creates "128"
im just wondering is it possible to create that? since im currently using "New-Item" and just giving it a path. i want my folder to named "RC4 40/128"
The easiest way will be invoking & REG ADD (basically, using CMD for the task) since PowerShell wants to interpret the forward slash as a delimiter. I just had a problem at work recently where I ran into this problem and could not find any solutions beyond that one.
A small tip: | Out-Null is a very slow operation and if you plan on calling anything with it to scale, I'd recommend using $Null = or [Void]( ... )
Normaly you must use:
New-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\" -Name "RC4 40/128" -PropertyType DWORD -Value 0
In this case it will we be:
AddMachineRegistry "HKLM:\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\" "RC4 40/128" 0
There is no need to backslashes the "/". Alternative: you can put path in ' ' instead " ". Commands in ' ' change special characters to normal chars.

How to set a binary registry value (REG_BINARY) with PowerShell?

How to set a binary registry value (REG_BINARY) with PowerShell?
Background:
I need to change some properties of the ASP.NET State service using a PowerShell script. Unfortunately, the built-in PowerShell cmdlet Set-Service only lets you modify the service description, startup type, display name, and status. I need to modify the Subsequent failures property found on the Recovery tab (when viewing the service's properties). I found that this value was stored in the registry as a REG_BINARY value.
An export of the value looks like this:
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\services\aspnet_state]
"FailureActions"=hex:50,33,01,00,00,00,00,00,00,00,00,00,03,00,00,00,0e,00,00,\
00,01,00,00,00,00,00,00,00,01,00,00,00,00,00,00,00,01,00,00,00,00,00,00,00
In Powershell there is a Set-ItemProperty cmdlet with which you can set registry value values. For a string or dword value, you can just pass a string or an int. I know which hex value in the array to change, but I can't figure out how to set a binary value.
The following line gives you an example how to create one
New-ItemProperty -Path . -Name Test -PropertyType Binary -Value ([byte[]](0x30,0x31,0xFF))
and how to change an existing one:
Set-ItemProperty -Path . -Name Test -Value ([byte[]](0x33,0x32,0xFF))
Is it just me who feels this misses the main part of this question?
How would you go about changing the original:
50,33,01,00,00,00,00,00,00,00,00,00,03,00,00,00,0e,00,00,\
00,01,00,00,00,00,00,00,00,01,00,00,00,00,00,00,00,01,00,00,00,00,00,00,00
Into a format like:
([byte[]](0x33,0x32,0xFF))
EDIT: After trying to get this working it turns out you just prefix all of the pairs with '0x'. Not sure why that was not mentioned in the answer. So just change the above to:
0x50,0x33,0x01,0x00,0x00,0x00,0x00,0x00... etc.
Then wrap that in the following:
([byte[]](0x50,0x33,0x01,0x00,0x00,0x00,0x00,0x00... etc.))
This post has helped me out with similar problem. Thanks!
Bringing xBr0k3n and Howard's answers together:
#Change these three to match up to the extracted registry data and run as Admin
$YourInput = "50,33,01,00,00,00,00,00,00,00,00,00,03,00,00,00,0e,00,00,00,01,00,00,00,00,00,00,00,01,00,00,00,00,00,00,00,01,00,00,00,00,00,00,00"
$RegPath = 'HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\services\aspnet_state'
$AttrName = "FailureActions"
$hexified = $YourInput.Split(',') | % { "0x$_"}
New-ItemProperty -Path $RegPath -Name $AttrName -PropertyType Binary -Value ([byte[]]$hexified)
Resurrecting this.
Here's how you can modify registry item binary values concisely in easy-to-follow powershell. In this example DefaultConnectionSettings is the registry item with a REG_BINARY value that we're trying to modify.
$path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections"
$objName = "DefaultConnectionSettings"
$getObj = Get-ItemProperty -path $path -name $objName
$getObj.DefaultConnectionSettings[8] = 1
$objValue = $getObj.DefaultConnectionSettings
Set-ItemProperty -path $path -name $objName -Value $objValue
When you use Get-ItemProperty for a registry item with a REG_BINARY value, it gives you a number of child objects in a collection.
By referencing the name of the item (in this case we do getObj.DefaultConnectionSettings) as a child object of getObj, we get an array of values, where each binary value (i.e 50,33,01,00,00,00,00,00,04) has its own position in the array.
Because it is an array we can reference, modify, and iterate through it easily by doing $getObj.DefaultConnectionSettings[8] = 1 or whatever number you want in place of 8. The 8 refers to the position of the value in the array. In the example of 50,33,01,00,00,00,00,00,04 the 9th position is 04. Remember that, like other things, arrays start counting at 0.
Setting it = 1 will change that 04 value in the binary to 01 while leaving the rest of the values unchanged in the array.
Finally, we set the change in place with Set-ItemProperty -path $path -name $objName -Value $objValue
Hope this helps others.
FYI, you can also set binary values with the PSRemoteRegistry PowerShell module (
http://psremoteregistry.codeplex.com/), on local or remote computers.
$Key = 'SOFTWARE\MyCompany'
Set-RegBinary -Hive LocalMachine -ComputerName Server1 -Key $Key -Value RegBinary -Data #([char[]]'PowerShell')
Let's start with an integer:
$int = 0xffffffff
Get the bytes:
$bytes = [bitconverter]::GetBytes($int)
Using set-itemproperty with the little knows '-type' parameter that can be used with registry paths:
Set-ItemProperty hkcu:\key1 bin1 $bytes -type binary
Get it back:
$bytes = Get-ItemProperty hkcu:\key1 bin1 | % bin1
Turn 4 bytes into an int:
$int = [bitconverter]::toint32($bytes, 0)
'0x{0:x}' -f $int
0xffffffff
I had problems with the other solutions, here's what I found to work:
Short Answer:
New-ItemProperty -path $path -name $name -value [byte]0x00,0x01,0x02 -PropertyType Binary
Complete Example:
$path = "HKCU:\Software\Hex-Rays\"
$name = "StrWinStringTypes"
$value = [byte]0x00,0x01,0x02
#if key path found, just add/modify the value/data pair
If (Test-Path($path))
{
New-ItemProperty -path $path -name $name -value $value -PropertyType Binary -Force | Out-Null
}
#if key path not found, create it first before adding value/data
Else
{
New-Item -path $path -force
New-ItemProperty -path $path -name $name -value $value -PropertyType Binary -Force | Out-Null
}