PowerShell: combining paths using a variable - powershell

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'

Related

How to change value of property in 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.

Using Powershell called from a bat file, Need to get owner/user of a windows process, but owner isn't showing up

I need to get the path and owner of certain processes on a remote computer and use a batch file to get it. So far, I've come up with something that gives me the path, but not the owner:
powershell -command "Get-WmiObject -Class win32_process -ComputerName myserver.mydomain.local -Filter 'name like """"%%myprocess%%""""' | select path,GetOwner"
For that, GetOwner is blank.
How can I get this to work or accomplish the same objective with another PS query or batch command?
GetOwner() is a method. User is a property returned by getowner() that is probably what you want.
set myprocess=powershell
powershell "Get-WmiObject win32_process -computername myserver.mydomain.local | where name -match %myprocess% | select path,#{n='Owner';e={$_.getowner().user}}"
Path Owner
---- -----
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe admin
Or you can use get-process. EDIT: Hmm looks like -computername and -includeusername can't go together. I can test it with "%computername%" but not "localhost".
powershell "get-process -computername %computername% -includeusername *%myprocess%* | select path,username"
Get-Process : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:1
+ get-process -computername DESKTOP-JQ7B7TZ -includeusername *powershel ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Process], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.GetProcessCommand
If remote powershell were working:
powershell "invoke-command myserver.mydomain.local { get-process -includeusername *%myprocess%* | select path,username }"
Path : C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
UserName : DESKTOP-JQ7B7TZ\admin
PSComputerName : myserver.mydomain.local
RunspaceId : b1bc87a7-1c21-4f91-a238-bbb68978ea6c

converting pom.xml version to number format

I have a requirement to increment to read and increment the pom.xml version by 1 using powershell script.
I was able to fetch the version value as for example: 1.0.123, but the type given here is string, when I try to convert it into Decimal or Double I am getting below error:
Code:
PS C:\Users\XXXX\Downloads> $finale
1.0.153
PS C:\Users\XXXX\Downloads> $finale.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
Error:
PS C:\Users\XXXX\Downloads> $finale1 = [Double]::Parse($finale)
Exception calling "Parse" with "1" argument(s): "Input string was not in a correct format."
At line:1 char:1
+ $finale1 = [Double]::Parse($finale)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : FormatException
The reason is 1.0.123 is not math. It is nether an integer, nor a double. It is simply a string that contains numbers and symbols. This is why you are getting the error.
See the following Help files:
About_Arithmetic_Operators
.NET Math Class
Using a [version] type is nice, but it is immutable. This code splits it into an array, increments the third (Build) number, and produces a string in $newfinale.
Note that this does not check to see if there is a third (Build) value. It will produce an exception if the $finale is '1.2'.
PS C:\> $finale = '2.3.4.5'
PS C:\> $a = $finale.split('.')
PS C:\> $a[2] = [int]$a[2] + 1
PS C:\> $newfinale = $a -join '.'
PS C:\> $newfinale
2.3.5.5

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']

Argument Exception with GetVersionInfo and powershell

I am trying to use powershell to get the file version of a file. If I right click the file and look at the version, it shows a value. Here is how I am trying to do it:
$path = "MSDE2000A";
$info = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($path);
Here is the exception information it is throwing:
Exception calling "GetVersionInfo" with "1" argument(s): "MSDE2000A.exe"
At line:1 char:58
+ $f = [system.diagnostics.fileversioninfo]::getversioninfo <<<< ("MSDE2000A.exe")
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Every file I've checked has the sames result. However, if my path is c:\windows\notepad.exe (as in the example) it works as expected. What's going on?
.NET and PowerShell's notion of current directory aren't always the same. Try passing in the absolute path.
[Diagnostics.FileVersionInfo]::GetVersionInfo('C:\Windows\System32\user32.dll')
ProductVersion FileVersion FileName
-------------- ----------- --------
6.1.7600.16385 6.1.7600.1638... C:\Windows\System32\user32.dll
Also, you can get this information with Get-ChildItem like so:
Get-ChildItem C:\Windows\System32\user32.dll | fl VersionInfo