Need help troubleshooting an the Array and Scriptblock OR Maybe this is better using param and functions???
Script Objective: To easily update the list of applications to be installed
Getting error below.
'
At C:\Temp\appinstall.ps1:7 char:10
$Firefox={
~
The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept
assignments, such as a variable or a property.
CategoryInfo : ParserError: (:) [], ParseException
FullyQualifiedErrorId : InvalidLeftHandSide
'
Start-Transcript -Append c:\Deploy\log.txt
$ProgressPreference = 'SilentlyContinue';
#Change App Name, Source, MSI/EXE, Argument
$AppArray= (
$Firefox={
$App= "Firefox";
$App_source= "https://download.mozilla.org/?product=firefox-latest&os=win64&lang=en-US";
$destination = "c:\Deploy\$App.exe";
$Argument= "/S";
},
$Chrome=
{
$App= "Chrome";
$App_source= "https://dl.google.com/tag/s/defaultbrowser/edgedl/chrome/install/GoogleChromeStandaloneEnterprise64.msi";
$destination = "c:\Deploy\$App.exe";
$Argument= "/norestart","/qn";
}
)
$InstallScriptBlock=
{
$installed = (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where { $_.DisplayName -Match "$App" });
$installed.displayname
if ($installed.displayname -Match $App) {
Write-Host "$software installed"
}else{
If ((Test-Path $destination) -eq $false) {
New-Item -ItemType File -Path $destination -Force
}
#install software
Invoke-WebRequest $App_source -OutFile $destination
Start-Process -FilePath "$destination" -ArgumentList "$Argument" -Wait
#Delete installer
Remove-Item -recurse "$destination"
}
}
ForEach ($Program in $AppArray) {Invoke-Command -ScriptBlock $InstallScriptBlock}
Stop-Transcript
CodePudding user response:
It looks like you're trying to create a nested hashtable (@{ ... }
), but your syntax is flawed - see the linked docs.
However:
It should suffice in your case to create an array of hashtables to iterate over with
foreach
There's no need to use a separate script block (
{ ... }
) - just use the body of theforeach
loop statement.- As an aside: While using
Invoke-Command
for local invocation of script blocks works, it usually isn't necessary, because&
, the call operator, will do (e.g.$sb = { 'hi' }; & $sb
).Invoke-Command
's primary purpose is to execute a script block on a remote machine.
- As an aside: While using
Generally, you can use variables as-is as command arguments, without enclosing them in
"..."
- even if their values contain spaces. E.g.,Write-Output $foo
is sufficient, no need forWrite-Output "$foo"
To put it all together:
# Create an array whose elements are hashtables.
$appArray = (
@{
App = ($thisApp = 'Firefox')
App_source = 'https://download.mozilla.org/?product=firefox-latest&os=win64&lang=en-US'
Destination = "c:\Deploy\$thisApp.exe"
Argument = '/S'
},
@{
App = ($thisApp = 'Chrome')
App_source = 'https://dl.google.com/tag/s/defaultbrowser/edgedl/chrome/install/GoogleChromeStandaloneEnterprise64.msi'
Destination = "c:\Deploy\$thisApp.exe"
Argument = '/norestart /qn'
}
)
foreach ($app in $appArray) {
# Note how $app.<key> is used to refer to the entries of the hashtable at hand,
# e.g. $app.App yields "Firefox" for the first hashtable.
$installed = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object { $_.DisplayName -Match $app.App }
$installed.displayname
if ($installed.displayname -Match $app.App) {
Write-Host "$($app.App) already installed."
}
else {
if ((Test-Path $app.Destination) -eq $false) {
New-Item -ItemType File -Path $app.Destination -Force
}
#install software
Invoke-WebRequest $app.App_source -OutFile $app.Destination
Start-Process -FilePath $app.Destination -ArgumentList $app.Argument -Wait
#Delete installer
Remove-Item -Recurse $app.Destination
}
}
Note:
I've removed unnecessary
;
and I've switched to using verbatim (single-quoted) strings ('...'
) when no string interpolation via expandable (double-quoted) strings ("..."
) is required, both for conceptual clarity and to avoid potentially unwanted expansions.Note the use of aux. variable
$thisApp
in theApp
key, which allows referencing it in the laterDestination
key, in an expandable string ("c:\Deploy\$thisApp.exe"
).- GitHub suggestion #13782 looks for a more elegant way to allow hashtable entries to reference one another.