How to change value of property in powershell - powershell

How do you access the value of a property in powershell and change its value
PS C:\Windows\system32> $tamp = get-item "HKLM:\SOFTWARE\Microsoft\AppServiceProtocols\ms-phone-api"
PS C:\Windows\system32> $tamp
Hive: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\AppServiceProtocols
Name Property
---- --------
ms-phone-api AppServiceName : com.microsoft.phone.api
PackageFamilyName : Microsoft.YourPhone_8wekyb3d8bbwe
PS C:\Windows\system32>
now that we have an item named ms-phone-api i would like to access the properties and change the values for them the registry path used here is just for the sake of explanation, any registry key can be used
I tried to access the values by using the following
$tamp.<property-name> = <value>
but this does not work and outputs this
PS C:\Windows\system32> $tamp.AppServiceName = com.google
com.google : The term 'com.google' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included,
verify that the path is correct and try again.
At line:1 char:25
+ $tamp.AppServiceName = com.google
+ ~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (com.google:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
PS C:\Windows\system32>

Using New-ItemProperty is the easiest way:
# get the RegPath
$RegPath = "HKLM:\SOFTWARE\Microsoft\AppServiceProtocols\ms-phone-api"
# set the Name we want to update
$Name = "ms-phone-api"
# set Value name we want to update
$Value = "AppServiceName"
New-ItemProperty -Path $RegPath -Name $Name -Value $Value -PropertyType String
You can read more details here: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/new-itemproperty?view=powershell-7.2

You can do
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\AppServiceProtocols\ms-phone-api' -Name 'AppServiceName' -Value 'com.google'
(you can also append -Type String)
The Set-ItemProperty cmdlet creates or changes the value of a property of an item.

Related

POWERSHELL - Module Active Directory command New-AdGroup Problem with Spaces in value OU="Servers Of Files"

I would need your help with the use of New-AdGroup command.
The goal of my script is to verify if an Active Directory group exists and if it doesn't exist the script create the group and add the member of the group in a specific OU.
But my problem is when I use the script with a combination of OU and one of them contains some spaces in its name (ex : "OU=Servers of Files"), the script returns an error.
Example: I need to add the group in "OU=Fileserver1" which is a sub OU of "OU=Servers of Files" which is a sub OU of "OU=Groupes".
When I call New-AdGroup with a path's value : "Ou=ServerFile1,OU=Servers of Files,OU=Groupes,DC=Contoso,DC=lan", I get the following error.
New-ADGroup : Objet de l’annuaire non trouvé At line:29 char:5
+ New-ADGroup -Name "$DLGroupName" -Path "$Orga" -GroupCategory "Se ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (CN=G_GROUP1...ONTOSO,DC=lan:String) [New-ADGroup],
ADIdentityNotFoundException
+ FullyQualifiedErrorId : Objet de l’annuaire non trouvé,Microsoft.ActiveDirectory.Management.Commands.NewADGroup
The problem is caused by "OU=Servers of Files" because I tried with an OU without spaces and it was working.
Please find a part of the script below, let me know how I can manage spaces under a path :
#Variable
$CurrentDomain = Get-ADDomain | Select -Property DistinguishedName
$TargetOU = "OU=FileServer1,OU=Servers of Files,OU=Groupes" #
$OrganizationalUnitDN = $TargetOU+","+ $CurrentDomain.DistinguishedName
$Orga = $OrganizationalUnitDN
$DLGroupName = "DL_FileServer1_TEST"
$Description = "\\FileServer1\Share\Test"
New-ADGroup -Name "$DLGroupName" -Path "$Orga" -GroupCategory "Security" -GroupScope "Global" -Description "$Description" -PassThru
Note : $Orga = Ou=ServerFile1,OU=Servers of Files,OU=Groupes,DC=Contoso,DC=lan
When we encounter weird bugs like this, a good first test is to manually run the command with no variables to find the root cause of the error. Doing this shows us that we don't need to escape spaces with a \ or \20 sequence and that route won't help us.
Because I can run your command with no errors when I manually expand the variables like so:
New-ADGroup -Name "DL_FileServer1_TEST" -Path "OU=Servers Of Files,DC=FoxDeploy,DC=local" `
-GroupCategory "Security" -GroupScope "Global" -Description "Test" -PassThru
DistinguishedName : CN=DL_FileServer1_TEST1,OU=Servers Of Files,DC=FoxDeploy,DC=local
GroupCategory : Security
GroupScope : Global
Name : DL_FileServer1_TEST1
ObjectClass : group
ObjectGUID : 5889f8ea-9d80-4609-ad47-92e50a574088
SamAccountName : DL_FileServer1_TEST1
SID : S-1-5-21-3818945699-900446794-3716848007-32100
Now that I know this works, I know I can then store the values in variables to make it cleaner to read, like this:
$params = #{
Name = "DL_FileServer1_TEST1";
Path = "OU=Servers Of Files,DC=FoxDeploy,DC=local";
GroupCategory = "Security";
GroupScope = "Global";
Description = "My Test Group"
PassThru = $true
}
New-ADGroup #params
If I had to guess, I bet that you need to run the entire script to populate all of the variables, and instead you are rerunning the last command over and over but one of the variables is $null.
If that doesn't work...
If not that, then are we sure the container of Ou=ServerFile1 actually exists too?

How to explicitly declare type of a variable when creating that variable with New-Variable function?

How can I cast myChar in New-Variable -Name myChar -Value "=" -Option ReadOnly to type [char], or (more generally) how can I specify type of a variable created with New-Variable?
Thanks
EDIT (credit goes to #veefu):
[char]$sampleVariable="A"
$sampleAttributes=(Get-Variable -Name sampleVariable).Attributes[0]
New-Variable -Name myVariable
(Get-Variable -Name myVariable).Attributes.Add($sampleAttributes)
$myVariable="ab" # GENERATES CONVERSION ERROR (WHICH HELPS A LOT)
$myVariable="a" # DOES NOT GENERATE CONVERSION ERROR (EVERYTHING'S FINE)
EDIT (credit goes to #postanote):
[char]$anyCharacter="A"
# FOLLOWING LINE GENERATES CONVERSION ERROR (GOOD THING)
Set-Variable -Name anyCharacter -Value "ab" -Option ReadOnly
# FOLLOWING LINE DOES NOT GENERATE CONVERSION ERROR (GREAT)
Set-Variable -Name anyCharacter -Value "a" -Option ReadOnly
This is pretty much impossible to do now in PowerShell so I've opened an issue You should be able to set the type conversion attribute on a variable with New-Variable to address this.
The difference between a variable with and without a type specifier [int32] is in the variable attributes:
[int32] $var1 = 32
$var2 = 'a'
Get-Variable -Name 'var1' | fl *
Get-Variable -Name 'var2' | fl *
yields:
Name : var1
Description :
Value : 32
Visibility : Public
Module :
ModuleName :
Options : None
Attributes : {System.Management.Automation.ArgumentTypeConverterAttribute}
Name : var2
Description :
Value : a
Visibility : Public
Module :
ModuleName :
Options : None
Attributes : {}
New-Variable doesn't support setting these attributes, so it isn't possible to make the equivalent of [int32] $myVarname using New-Variable
It is possible to use the .net [psvariable]::new() constructor to create a variable with these attributes. I could not figure out how to construct the Attributes from scratch to make the equivalent of [int32], but was able to successfully copy attributes from another variable during construction:
[int32] $int32ConstrainedVar1 = 32
$var1Attributes = (Get-Variable -Name 'int32ConstrainedVar1').Attributes
$newConstrainedVar = [psvariable]::new('int32ConstrainedVar2', 33, 'None', $var1Attributes)
After this, trying to assign something that cannot be converted to [int32] fails, as expected:
$newConstrainedVar.Value = 'asdf'
yields:
Exception setting "Value": "Cannot convert value "asdf" to type "System.Int32". Error: "Input string was not in a correct format.""
At line:1 char:1
+ $newConstrainedVar.Value = 'asdf'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
Sorry for the sketchy details; this is a level of powershell internals that's new to me.
I'm interested in what your use case is; The only reason I can imagine you'd want to work at this low a level with powershell is if you're writing a runtime that translates from another language into powershell.
There is not native way using the cmdlet alone to do this as per its specification:
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/new-variable?view=powershell-6
[-Name] <String>
[[-Value] <Object>]
[-Description <String>]
[-Option <ScopedItemOptions>]
[-Visibility <SessionStateEntryVisibility>]
[-Force]
[-PassThru]
[-Scope <String>]
[-WhatIf]
[-Confirm]
[<CommonParameters>]
After thinking about this a bit, one could apply the datatype after the create or inline, this way...
(might be a way for you, relative to your use case, but again...)
[char](New-Variable -Name myChar -Value "=")
$myChar
=
$myChar.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
Remove-Variable -Name myChar
[int](New-Variable -Name myChar -Value 1)
0
$myChar
1
$myChar.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Int32 System.ValueType
Remove-Variable -Name myChar
[decimal](New-Variable -Name myChar -Value 10.00)
0
$myChar
10.00
$myChar.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Double System.ValueType
Remove-Variable -Name myChar
Variable type
Usually when you create a variable you implicitly set the type by the value you use. Sometimes though you may want to explicitly set the variable type.
if you don’t give the variable a type you can do this:
PS> $x = 35
PS> $x
35
PS> $x = 'now a string'
PS> $x
now a string
If you give the variable an explicit type
PS> [int]$x = 35
PS> $x
35
PS> $x = 'now a string'
Cannot convert value "now a string" to type "System.Int32". Error: "Input string was not in a correct format."
At line:1 char:1
+ $x = 'now a string'
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException
The variable expects an integer or something that can be converted to an integer
PS> $x = '123'
PS> $x
123
You can’t supply a type when you use New-Variable so if you need a read only or constant variable then create it as shown above then use Set-Variable to make it read only or constant.
https://blogs.msmvps.com/richardsiddaway/2018/08/18/variable-type
So, this still comes back to my earlier statement...
one could apply the datatype after the create …
Set-Variable just did not come to mind in my earlier post.
So it is possible, i found a way.
Make a string the standard way:
[string]$var1 = 1
$var1.GetType().name
Make a string with set-variable:
Set-Variable -Name var2 -Value (New-Object -TypeName System.String -ArgumentList "1")
$var2.GetType().name
It also works with other objects:
Set-Variable -Name var3 -Value (New-Object 'System.Collections.Generic.List[System.Object]')

diskusage how to use in powershell

I am very new to powershell and writing a script which will go to each computer in windows domain and get the size of a user profile. I have tried below on a powershell script
$profileDir = "\\$computerName\c$\users\userProfile"
$fullProfile = (Get-ChildItem $profileDir -recurse -force | Measure-Object -property length -sum)
But on some computer it gives below error. The problem seems that some directories on the profile have a long path and get-ChildItem fails
Get-ChildItem : The specified path, file name, or both are too long. The fully
qualified file name must be less than 260 characters, and the directory name mu
st be less than 248 characters.
At C:\scripts\powershell\profiles.ps1:56 char:30
+ $fullProfile = (Get-ChildItem <<<< $profileDir -recurse -force | Measure-Obj
ect -property length -sum)
+ CategoryInfo : ReadError: (\\computerName...nt.IE5\RQT4K4JU:St
ring) [Get-ChildItem], PathTooLongException
+ FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChil
dItemCommand
##########################################################################################################################
At this point I tried using du.exe (diskusage) from SysInternals which works fine but I don't know how to take the output of du into a variable. I have below on my script
$dirSize = .\du.exe -c c:\temp |convertFrom-csv | select-object DirectorySize
write-host $dirSize
The output is
PS C:\scripts\powershell> .\profiles.ps1
#{DirectorySize=661531}
What I want the output to be like
PS C:\scripts\powershell> .\profiles.ps1
661531
What you have is a hashtable. You need to reference the item in that hashtable to get it's value. Instead of:
Write-Host $dirSize
Try:
$dirSize['DirectorySize']

PowerShell: combining paths using a variable

This must be something obvious, but I can't get this to work.
I'm trying to build a variable that should contain the path to an existing file, using an environment variable ($env:programfiles(x86)). However I keep getting errors, and I fail to see why.
This works fine (if the file exists):
PS C:\> $f = "C:\Program Files (x86)" + '\sometextfile.txt'
PS C:\> $f
C:\Program Files (x86)\sometextfile.txt
PS C:\> gci $f
Directory: C:\Program Files (x86)
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 13/12/2010 14:03 0 sometextfile.txt
PS C:\>
However, this does not:
PS C:\> "$env:programfiles(x86)"
C:\Program Files(x86)
PS C:\> $f = "$env:ProgramFiles(x86)" + '\sometextfile.txt'
PS C:\> $f
C:\Program Files(x86)\sometextfile.txt
PS C:\> gci $f
Get-ChildItem : Cannot find path 'C:\Program Files(x86)\sometextfile.txt' because it does not exist.
At line:1 char:4
+ gci <<<< $f
+ CategoryInfo : ObjectNotFound: (C:\Program Files(x86)\sometextfile.txt:String) [Get-ChildItem], ItemNot
FoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
What's happening, and how do I fix it?
Here is what is going on...
In any Windows PowerShell path empty characters or spaces need to be surrounded with a set of quotes or brackets. The PowerShell environment variable for the C:\Program Files (x86) is ${env:ProgramFiles(x86)}, not $env:ProgamFiles(x86) since PowerShell needs to escape the empty spaces in the real path.
If you use the '${env:ProgramFiles(x86)}' explicit environment variable, it works perfectly.
This won't work...
PS C:\> cd "$env:programfiles(x86)"
Set-Location : Cannot find path 'C:\Program Files(x86)' because it does not e
At line:1 char:3
+ cd <<<< "$env:programfiles(x86)"
+ CategoryInfo : ObjectNotFound: (C:\(x86):String)
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.
or this...
PS C:\> $env:ProgramFiles(x86)
Unexpected token '(' in expression or statement.
At line:1 char:19
+ $env:ProgramFiles( <<<< x86)
+ CategoryInfo : ParserError: ((:String) [], Parent
+ FullyQualifiedErrorId : UnexpectedToken
But this works great...
PS C:\> ${env:ProgramFiles(x86)}
C:\Program Files (x86)
PS C:\> $f = "${env:ProgramFiles(x86)}" + "\sometextfile.txt"
PS C:\> $f
C:\Program Files (x86)\sometextfile.txt
PS C:\> gci $f
Directory: C:\Program Files (x86)
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 12/13/2010 8:58 AM 0 sometextfile.txt
That is weird and looks like a bug. Actually it is resolving the $env:programfiles variable and appending the rest of the string - which in this case just happens to be (x86).
This will work though:
$f = ${env:ProgramFiles(x86)} + '\sometextfile.txt'

Error retrieving registry value with Powershell

I'm attempting to read a value from a registry entry with Powershell. This is fairly simple, however, one particular registry key is giving me trouble.
If I run the following, I can't get the value of the (default) of "$setting".
C:\Program Files\PowerGUI> $setting = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping\Autorun.inf"
C:\Program Files\PowerGUI> $setting
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\
CurrentVersion\IniFileMapping\Autorun.inf
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\
CurrentVersion\IniFileMapping
PSChildName : Autorun.inf
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
(default) : #SYS:DoesNotExist
Normally, I would do $setting.Attribute, or $setting.(default). However, that results in the following error:
C:\Program Files\PowerGUI> $setting.(default)
The term 'default' is not recognized as a cmdlet, function, operable program, or script file. Verify the term and try again.
At :line:1 char:17
+ $setting.(default <<<< )
How do I get the value of the "(default)" attribute?
Thanks in advance.
EDIT Had to look through and old script to figure this out.
The trick is that you need to look inside the underlying PSObject to get the values. In particular look at the properties bag
$a = get-itemproperty -path "HKLM:\Some\Path"
$default = $a.psobject.Properties | ?{ $_.Name -eq "(default)" }
You can also just use an indexer instead of doing the filter trick
$default = $a.psobject.Properties["(default)"].Value;
Another version:
(Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping\Autorun.inf').'(default)'
Use Get-Item to get an object representing the registry key:
PS > $regKey = Get-Item HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping\Autorun.inf
This gives you an instance of RegistryKey. RegistryKey has a method named GetValue; if the argument to GetValue is the empty string (''), then it will return the (default) value:
PS > $regKey.GetValue('')
Why is this better than Get-ItemProperty? It extends more naturally to Get-ChildItem. Get-ChildItem will give you a list of RegistryKey objects. In my particular case, I wanted to list the install paths of the versions of Python installed on my machine:
PS C:\> get-childitem HKLM:\SOFTWARE\Wow6432Node\Python\PythonCore\*\InstallPath `
>> | foreach-object { $_.GetValue('') }
C:\Python26\ArcGIS10.0\
C:\Python\27\