Powershell refer to dynamic variable name - powershell

I have a reason why I don't want to use an array. But is it possible to use variable folder$i in the Remove-Item command
Set-Variable -Name "folder1" -Value "c:\windows\temp\1\*"
Set-Variable -Name "folder2" -Value "c:\windows\temp\2\*"
Set-Variable -Name "folder3" -Value "c:\windows\temp\3\*"
for ($i=1; $i -le 3; $i++)
{
Write-Host "folder to delete : Remove-Item –path folder$i -recurse"
Write-Host "$(folder$i)"
Remove-Item –path "$(folder$i)" -recurse
}

generally speaking, NOT using an array for this is ... a really good self-foot-gun situation. [grin]
however, if you have found some bizarre reason to NOT use the logical method, the following will work. it uses the Get-Variable cmdlet to do the actual work.
$Var1 = 'Variable_One'
$Var2 = 'Two_Variable'
foreach ($Index in 1..2)
{
Get-Variable -Name "Var$Index" -ValueOnly
}
output ...
Variable_One
Two_Variable

Related

Deployment of PowerShell scripts through Intune not working properly?

I made a simple PowerShell script to change the taskbar settings (Hiding the Search and Task View buttons, as well as alignment). I was able to get them to push out properly, however on first run the scripts would only partially work, the Task View button would be removed however the other ones wouldn't.
The script would work however when you would manually change the taskbar settings through the GUI, for example switching the alignment to left and then back to center, the script would then work and adjust the alignment back to the left side. I just need to find what's causing it not to run properly the first time when units are deployed.
This short script goes as follows:
Set-ExecutionPolicy bypass -Scope CurrentUser
$registryPath1 = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Search"
$registryPath2 = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
$registryPath3 = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
$name1 = "SearchboxTaskbarMode"
$name2 = "ShowTaskViewButton"
$name3 = "TaskbarAl"
$value1 = "0"
$value2 = "0"
$value3 = "0"
IF(!(Test-Path $registrypath1))
{
New-Item -Path $registryPath1 -Force | Out-Null
Set-ItemProperty -Path $registryPath1 -Name $name1 -Value $value1 `
}
ELSE {
Set-ItemProperty -Path $registryPath1 -Name $name1 -Value $value1 `
}
IF(!(Test-Path $registryPath2))
{
New-Item -Path $registryPath2 -Force | Out-Null
Set-ItemProperty -Path $registryPath2 -Name $name2 -Value $value2 `
}
ELSE {
Set-ItemProperty -Path $registryPath2 -Name $name2 -Value $value2 `
}
IF(!(Test-Path $registryPath3))
{
New-Item -Path $registryPath3 -Force | Out-Null
Set-ItemProperty -Path $registryPath3 -Name $name3 -Value $value3 `
}
ELSE {
Set-ItemProperty -Path $registryPath3 -Name $name3 -Value $value3 `
}

Make a registry change based on OS version

I am trying to make a reg key change based on the OS version.
The Key change pat works fine however the if function to work out if the device needs it or not I can not get to work. Any advice would be helpful. The powershell is below.
$verCheckOS = (Get-WmiObject win32_operatingsystem).version
if ($verCheckOS -lt 10.0.19043 -and $verCheckOS -gt 10.0.17134)
{
if (Test-Path HKLM:\SOFTWARE\Policies\Microsoft\AzureADAccount)
{
CD HKLM:\SOFTWARE\Policies\Microsoft
New-Item -Name AzureADAccount
New-ItemProperty -Path "AzureADAccount" -Name "AllowPasswordReset" -Value 1 -PropertyType DWord
}
}
Else
{
}
To make PowerShell compare version numbers properly you need to cast them to the proper type.
$verCheckOS = [version](Get-CimInstance -ClassName CIM_OperatingSystem).Version
if ($verCheckOS -lt [version]'10.0.19043' -and $verCheckOS -gt [version]'10.0.17134') {
if (-not (Test-Path HKLM:\SOFTWARE\Policies\Microsoft\AzureADAccount)) {
Push-Location 'HKLM:\SOFTWARE\Policies\Microsoft'
New-Item -Name 'AzureADAccount'
New-ItemProperty -Path 'AzureADAccount' -Name 'AllowPasswordReset' -Value 1 -PropertyType DWord
}
}
$verCheckOS = (Get-WmiObject win32_operatingsystem).version
if ($verCheckOS -lt "10.0.19043" -and $verCheckOS -gt "10.0.17134")
{
if (!(Test-Path "HKLM:\SOFTWARE\Policies\Microsoft\AzureADAccount"))
{
$null = New-Item -Name "AzureADAccount" -Path "HKLM:\SOFTWARE\Policies\Microsoft\"
$null = New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\AzureADAccount" -Name "AllowPasswordReset" -Value 1 -PropertyType DWord
}
}
I am a bit confused by your code. You check if the full path to the AzureADAccount key exists and then if it does you proceed to try and create it? I think you meant if it does NOT exist then create it? I mean your code won't execute if it isn't there so the line to create it is just going to error out. So I changed it to run the block only if the path doesn't exist. If that's wrong then put the Test-Path line back the way you had it and remove the 'New-Item -Name "AzureADAccount"' line as its meaningless and keep the New-ItemProperty line.
Also just adding quotes around the numbers made the version check if statement work fine for me in my testing.

Extra characters when script is run as local system

I have a script with a couple of functions. The first function creates some registry keys in HKLM\Software\Test (\UDF1-30). The second function takes any strings written in the UDF# keys, contatinates them (one line per UDF, seperated by the pipe character) and copies them to HKLM\Software\CentraStage\Custom#.
For testing, I threw the following string into UDF12:
PatchSched:{"StartTime":"23:00:00","TzBias":-480,"Duration":240,"DayOfYear":[],"DayOfWeek":[-2],"Days":[],"MonthlyDayOfWeek":[6],"Months":[1,2,3,4,5,6,7,8,9,10,11,12],"Ordering":[4],"ScheduleType":7}
When I run the script as the local administrator, I get that same string into Custom12. But, when I run the script as the Local System, I get random pipes in the string:
PatchSched:{"StartTime":"23:00:00","TzBias":-480,"Duration":240,"DayOfYear":[],"DayOfWeek":[-2],"Days":[],"MonthlyD|ayOfWeek":[6],"Months":[1,2,3,4,5,6,7,8,9,10,11,12],"Ordering":[4],"ScheduleType":7}
Why in the world, would this happen? Here is the script:
Function Add-UserDefinedFields {
<#
.DESCRIPTION
This function checks if HKLM\SOFTWARE\Test exists. If not, it creates the required registry structure, to support Update-UserDefinedFields.
#>
Set-Location HKLM:
If (-Not(Test-Path .\Software\Test\UDF29)) {
# If the Test registry key does not exist...
# Create the Test registry key.
New-Item -Path .\Software -Name Test
# Create 30 UDF registry keys.
For ($i = 1; $i -le 30; $i++) {
New-Item -Path .\Software\Test -Name UDF$i
}
}
}
Function Update-UserDefinedFields {
<#
.DESCRIPTION
This function reads the value of each UDF registry entry, in HKLM\SOFTWARE\Test and writes the value(s) to the corresponding UDF in HKLM\SOFTWARE\CentraStage.
#>
Set-Location HKLM:
For ($i = 1; $i -le 30; $i++) {
# For each of the 30 UDF registry keys...
# Initialize variable.
$udfValue = New-Object "System.Collections.Generic.List[string]"
Get-ItemProperty .\SOFTWARE\Test\UDF$i -ErrorAction SilentlyContinue | Out-String -Stream | Where-Object { $_ -NOTMATCH '^ps.+' } | ForEach-Object {
$udfValue.Add($_)
}
$udfString = $udfValue -join '|'
$udfString = $udfString.Replace(' ', '')
While ($udfString -like "*||*") {
$udfString = $udfString.replace('||', '|')
}
If ($udfString) {
# Trim the leading and trailing characters (|).
$udfString = $udfString.substring(1, $udfString.length - 2)
}
Write-Host ("Writing to UDF{0}: {1}" -f $i, $udfString)
# For each Test UDF, write the concatinated value to the corresponding AEM UDF registry location.
$null = New-ItemProperty -Path .\SOFTWARE\CentraStage -Name Custom$i -PropertyType String -Value $udfstring -Force -ErrorAction SilentlyContinue
}
}
Add-UserDefinedFields
Update-UserDefinedFields
Okay, I figured it out. The code now looks like this:
Function Add-TestUserDefinedFields {
<#
.DESCRIPTION
This function checks if HKLM\SOFTWARE\Test exists. If not, it creates the required registry structure, to support Update-UserDefinedFields.
#>
Set-Location HKLM:
If (-Not(Test-Path .\Software\Test\UDF29)) {
# If the Test registry key does not exist...
# Create the Test registry key.
New-Item -Path .\Software -Name Test
# Create 30 UDF registry keys.
For ($i = 1; $i -le 30; $i++) {
New-Item -Path .\Software\Test -Name UDF$i
}
}
}
Function Update-UserDefinedFields {
<#
.DESCRIPTION
This function reads the value of each UDF registry entry, in HKLM\SOFTWARE\Test and writes the value(s) to the corresponding UDF in HKLM\SOFTWARE\CentraStage.
#>
Set-Location HKLM:
For ($i = 1; $i -le 30; $i++) {
# For each of the 30 UDF registry keys...
# Initialize variable.
$udfValue = New-Object "System.Collections.Generic.List[string]"
(Get-ItemProperty .\SOFTWARE\Test\UDF$i -ErrorAction SilentlyContinue).PSObject.Properties | Where-Object { $_.Name -NOTMATCH '^ps.+' } | ForEach-Object {
$udfValue.Add("$($_.Name):$($_.Value)")
}
$udfString = $udfValue -join '|'
Write-Output ("The value of `$udfString is {0}" -f $udfString) | out-file C:\Synoptek\test.txt -Append
$udfString = $udfString.Replace(' ', '')
While ($udfString -like "*||*") {
$udfString = $udfString.replace('||', '|')
}
Write-Output ("Writing to UDF{0}: {1}" -f $i, $udfString)
# For each Test UDF, write the concatinated value to the corresponding UDF registry location.
$null = New-ItemProperty -Path .\SOFTWARE\CentraStage -Name Custom$i -PropertyType String -Value $udfstring -Force -ErrorAction SilentlyContinue
}
}
Add-TestUserDefinedFields
Update-UserDefinedFields

powershell add-member using pipeline and using $this property for value of new property

I'm novice with powershell and do not understand why this process works:
$ftpFiles = Get-FTPChildItem -Session $Session -Path "/myroot" -Recurse | ForEach-Object { $_ | Add-Member -type NoteProperty -name CompareFullName -value ($_.FullName -Replace "ftp://ftp.server.com/myroot/", "") -PassThru }
And this does not work:
$ftpFiles = Get-FTPChildItem -Session $Session -Path "/myroot" -Recurse | Add-Member -type NoteProperty -name CompareFullName -value ($_.FullName -Replace "ftp://ftp.server.com/myroot/", "") -PassThru
I try to add a property (CompareFullName) to the file object with value that uses another property of the same file object (FullName).
Add-Member was supposed to accept piped values.
what happens in the non-working syntax is that the property is added alright but the value is null.
The first syntax works OK.
I would appreciate an explanation or another way to achieve my goal without using foreach-object.
$_ is an automatic variable that only has meaning within a script block that executes on each item in the pipeline. The first example works because when you pipeline to ForEach-Object, $_ is defined for the script block. The second example does not work because there is no script block so $_ is undefined. AFAIK there is no way to do this without a foreach. You need something to compute a value for each item in the pipeline and Add-Member does not accept a script block to compute a value for the members it attaches. I guess you use a ScriptProperty like so:
$ftpFiles = Get-FTPChildItem -Session $Session -Path "/myroot" -Recurse | Add-Member -type ScriptProperty -name CompareFullName -value {$this.FullName -Replace "ftp://ftp.server.com/myroot/", ""} -PassThru
but this is semantically different than what you have, since it computes the property value every time it accessed.
Depending on what you are trying to do, you could use Select-Object to pull off the useful properties for use later:
$ftpFiles = Get-FTPChildItem -Session $Session -Path "/myroot" -Recurse | select *, #{n="CompareFullName"; e={$_.FullName -replace "ftp://ftp.server.com/myroot/", ""}}
This would produce new custom objects with the same properties, and an additional property, 'CompareFullName'.
This bit:
... -Recurse | ForEach-Object { $_ | Add-Member ...
^^^^^^^^^^^^^^^^^^^^^-- this bit!
...is omitted/cut/missed/elided/skipped from the second example:
... -Recurse | Add-Member ...
^-- is missed here!

How to disable autorun for all drives

I need to run a powershell script that disables autorun for ALL drives on a computer.
It can be done manually as described here, but I need to do it for multiple computers (with Windows XP and 7) using a WDS server.
Give this a try:
$path ='HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\Explorer'
Set-ItemProperty $path -Name NoDriveTypeAutorun -Type DWord -Value 0xFF
you can try this:
function Disable-AutoRun
{
$item = Get-Item `
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\IniFileMapping\AutoRun.inf" `
-ErrorAction SilentlyContinue
if (-not $item) {
$item = New-Item "REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\IniFileMapping\AutoRun.inf"
}
Set-ItemProperty $item.PSPath "(default)" "#SYS:DoesNotExist"
}
and this to re-enable:
function Enable-AutoRun
{
Remove-Item "REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\IniFileMapping\AutoRun.inf" -Force
}
Explication.