Install Google Chrome with Powershell

Install Google Chrome with Powershell

Reading Time: < 1 minute

My last weekly challenge to myself was to deploy google chrome with Powershell. This one was the hardest because it was hard to find the latest and greatest MSI 64 bit of google chrome. The coding wasn’t too hard after that. How google chrome works, follows suit the same way as firefox did.

The Script

$ChromeSource = "http://dl.google.com/tag/s/defaultbrowser/edgedl/chrome/install/GoogleChromeStandaloneEnterprise64.msi"
$Installer = "$ENV:TEMP\Google.msi"
Invoke-WebRequest -Uri $ChromeSource -OutFile $Installer
Get-Process -Name "Chrome" | Stop-Process -Force
msiexec /i $Installer /qn /norestart
Remove-Item $Installer

The Breakdown

We first start off getting the latest enterprise edition of google chrome. This is the 64-bit version thus the most stable version on them all. This is the version I would install everywhere in a company if I had a choice.

$ChromeSource = "http://dl.google.com/tag/s/defaultbrowser/edgedl/chrome/install/GoogleChromeStandaloneEnterprise64.msi"

Then we create the installer path and download the file using the Invoke-webrequest with the Outfile as the installer path.

$Installer = "$ENV:TEMP\Google.msi"
Invoke-WebRequest -Uri $ChromeSource -OutFile $Installer

Then we stop the google chrome process and install the latest version of google chrome using the msiexec command. Then we remove the installer.

Get-Process -Name "Chrome" | Stop-Process -Force
msiexec /i $Installer /qn /norestart
Remove-Item $Installer

That’s it. Very simple very straightforward. If you need to uninstall before installing (My testing was a success with overlapping the installers) then you can do the following before Installing google chrome:

$Chrome = Get-CimInstance win32_Product | where-object {$_.name -like "*Google*Chrome*"}
$Chrome | Invoke-CimMethod -MethodName Uninstall

Install Firefox with Powershell

Install Firefox with Powershell

Reading Time: < 1 minute

Need to deploy the latest version of firefox to 1000 machines, Here is a little powerhouse script that can do just that. It’s similar to my last script (Gimp) as it downloads directly from the web. This time we don’t have to parse out a website since Modzilla has it laid out before us.

The Script

$FirefoxSource = "https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US"
$Installer = "$ENV:TEMP\ModzillaFirefox.exe"
Invoke-WebRequest -Uri $FirefoxSource -OutFile $Installer
Get-Process -Name "*firefox*" | Stop-Process -Force
Start-Process -FilePath $Installer -ArgumentList "/s" -Verb runas -wait
Remove-Item $Installer

The Breakdown

The source is awesome. We are downloading directly from the site with their latest 64-bit product. This time we are going with the temporary file and then downloading the file with invoke-webrequest. Then we start the process of installing it with the /s flag which means silent. Since we are coming from the temp folder I threw in the runas flag to run it as the system. This way it installs for all users. Next, we set the wait flag to install the system. From everything I have read, we don’t need to uninstall the previous version to install the newest version. We do however have to stop the process that’s why we have a get process and stop process above. Finally, we remove the installer. That’s it. A lot simpler than Gimp.

Install Gimp with Powershell

Install Gimp with Powershell

Reading Time: 3 minutes

This little script installs the latest version of gimp 2.10 onto your Windows machine. Let’s take a look at the script and then break it down.

The Script

$DownloadPath = "C:\Temp\Gimp"
If (!(Test-Path -Path "C:\Temp\")) {New-Item -Path c:\ -Name Temp -ItemType Directory }
If (!(Test-Path -Path "C:\Temp\Gimp\")) {New-Item -Path c:\Temp -Name Gimp -ItemType Directory }
$URL = "https://download.gimp.org/mirror/pub/gimp/v2.10/windows/"
$Gimp = Invoke-WebRequest -UseBasicParsing -Uri $URL -SessionVariable websession
$Links = $Gimp.Links | Where-Object {$_.href -like "*.exe"} | select-object -Last 1
$URLDownload = "$URL$($Links.href)"
$DownloadName = "$DownloadPath\Gimp.exe"
Invoke-WebRequest -Uri $URLDownload -OutFile $DownloadName
if (Test-path "C:\Program Files\GIMP 2") {
    Get-Process -Name "Gimp*" | Stop-Process
    Start-Process -FilePath "C:\Program Files\GIMP 2\uninst\unins000.exe" -ArgumentList "/VERYSILENT" -wait
}
Start-Process -FilePath $DownloadName -ArgumentList '/VERYSILENT /NORESTART /ALLUSERS' -wait
Remove-Item $DownloadName

The Breakdown

The first thing we do is set up the path we want to make. Then we test to see if the path exists. If they don’t, we make them. I’m using temp in this cause because I will be deploying this to 2000+ machines. We will remove the installer afterward. I want the Temp folder to existing afterward for future deployments.

$DownloadPath = "C:\Temp\Gimp"
If (!(Test-Path -Path "C:\Temp\")) {New-Item -Path c:\ -Name Temp -ItemType Directory }
If (!(Test-Path -Path "C:\Temp\Gimp\")) {New-Item -Path c:\Temp -Name Gimp -ItemType Directory }

Next, we grab the URL we want to work with This is the gimp’s official download portal. This portal is by default Oldest to newest when you pull from it using Powershell.

$URL = "https://download.gimp.org/mirror/pub/gimp/v2.10/windows/"

Then we use the Invoke-webrequest to grab the website as we did in a previous post. From there we grab all of the links. In this case, since it’s a repo, they are all download links except for 2. We only want the exes of the list, so we use a where-object to find those. Then we select the last 1 as it is the newest version.

$Gimp = Invoke-WebRequest -UseBasicParsing -Uri $URL -SessionVariable websession
$Links = $Gimp.Links | Where-Object {$_.href -like "*.exe"} | select-object -Last 1

Now we need to build our URL and our Path. This is some string controls. Notice the $($Something.Something) in this code. When you deal with an array in a string and want to grab a sub item, you need to call it out with the $().

$URLDownload = "$URL$($Links.href)"
$DownloadName = "$DownloadPath\Gimp.exe"

Next we download the Gimp 2.10 version we are wanting with another invoke-webrequest. This time we select the Outfile tab.

Invoke-WebRequest -Uri $URLDownload -OutFile $DownloadName

Now we want to uninstall the pervious version of Gimp. Since gimp doesn’t show up in the win32_products, we go to it manually in the file system. Newer gimps host themselves inside the program files > gimp 2. So we search to see if that folder exists with a test-path. If it does, we then check to see if gimp is running. Then kill it with fire… ok, not fire, but force. Gimp is awesome about putting an uninstaller inside the file system. So we will use that. It’s located in the Gimp 2 > Uninst > Unins000.exe. Which can be triggered with a /verysilent parameter to keep it quiet. We do this with a start process and we use a flag -wait to wait on it to uninstall.

if (Test-path "C:\Program Files\GIMP 2") {
    Get-Process -Name "Gimp*" | Stop-Process -Force
    Start-Process -FilePath "C:\Program Files\GIMP 2\uninst\unins000.exe" -ArgumentList "/VERYSILENT" -Wait
}

Then we start the install of the new gimp with the start-process again. We use the Download Name we made eailer with an argument list of /verysilent /norestart /allusers and a -wait.

Start-Process -FilePath $DownloadName -ArgumentList '/VERYSILENT /NORESTART /ALLUSERS' -Wait

Finally we remove the installer with a remote-item.

Remove-Item $DownloadName

That’s all it takes yall. I hope this is helpful to you.

SHD – Quickbook Search

SHD – Quickbook Search

Reading Time: 2 minutes

This past week I needed to find all of the quickbook files on a computer without accessing quickbooks itself. The core of the script is a simple Get-Childitem command looped for each logical disk on the machine. Looking for one of the four main extensions for quickbooks. The four extensions are as follows

NameExtension
Company Filesqbw
Backup Filesqbb
Portable Filesqbm
Bank Statement filesqbo

The Script

function Search-QuickbookFiles {
    [cmdletbinding()]
    Param (
        [parameter(Mandatory = $True)][Validateset("Company Files", "Backup Files", "Portable Files", "Bank Statement Files")][string]$FileType
    )
    if ($FileType -like "Company Files") { $EXT = "QBW" }
    if ($FileType -like "Backup Files") { $EXT = "QBB" }
    if ($FileType -like "Portable Files") { $EXT = "QBM" }
    if ($FileType -like "Bank Statement Files") { $EXT = "QBO" }

    $Disks = Get-CimInstance -ClassName win32_logicaldisk 
    $QB = foreach ($Disk in $Disks) {
        Get-ChildItem -Path "$($Disk.DeviceID)\" -Filter "*.$EXT" -Recurse | Select-Object FullName,Length,LastWriteTime
    }
    $QB
}
$DateTime = (Get-Date).tostring("yyyy-MM-dd_hh-mm-ss")
if (!(Test-Path C:\temp)) {mkdir c:\temp}
Search-QuickbookFiles -FileType 'Company Files' | Export-Csv "c:\temp\$($Env:COMPUTERNAME)_CompanyFiles_$($DateTime).CSV"
Search-QuickbookFiles -FileType 'Backup Files' | Export-Csv "c:\temp\$($Env:COMPUTERNAME)_BackupFiles_$($DateTime).CSV"
Search-QuickbookFiles -FileType 'Portable Files' | Export-Csv "c:\temp\$($Env:COMPUTERNAME)_PortableFiles_$($DateTime).CSV"
Search-QuickbookFiles -FileType 'Bank Statement Files' | Export-Csv "c:\temp\$($Env:COMPUTERNAME)_BankStatementFiles_$($DateTime).CSV"

The Breakdown

Since I want this to be a little easier to use, I broke it down between the file types with a validate set parameter. This way you can choose which extension you want. Then I go through each extension and make an if statement for each one matching up the extension.

Next we get the disks using the Get-CimInstance -classname win32_logicaldisk. This grabs all the mapped drives, local drives, and anything else that has a drive letter.

Now we loop through those disks and search the root of each drive for any files with the extension we choose. We select the fullname as this gives us the full path. I also like having file size and last write time to determine if the file is valid still. Once we go through this loop we display the information.

Improvements

I can add remote computers to this setup.

That’s it, if you have any questions feel free too reach out.

SHD Resource – User to Groups

SHD Resource – User to Groups

Reading Time: 2 minutes

This little guy is a simple dynamic parameter resource for you all. Take a look at my previous blog post about how these parameters work. Totally worth adding these things to your scripts. This script is simple, it uses the add-adgroupmemeber and dynamic parameters to help pad against mistakes.

The Script

function Set-SHDADGroupMemebers {
    [cmdletbinding()]
    param (
        [parameter(mandatory=$true)][validateset('Add','Remove')][string]$Action,
        [securestring]$Credential,
        [switch]$Output
    )
    DynamicParam {
        
        
        # Set the dynamic parameters' name
        $ParamName_portgroup = 'Group'
        # Create the collection of attributes
        $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
        # Create and set the parameters' attributes
        $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
        $ParameterAttribute.Mandatory = $true
        # Add the attributes to the attributes collection
        $AttributeCollection.Add($ParameterAttribute) 
        # Create the dictionary 
        $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
        # Generate and set the ValidateSet 
        $arrSet = (Get-ADGroup -Filter *).name
        $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)    
        # Add the ValidateSet to the attributes collection
        $AttributeCollection.Add($ValidateSetAttribute)
        # Create and return the dynamic parameter
        $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_portgroup, [string], $AttributeCollection)
        $RuntimeParameterDictionary.Add($ParamName_portgroup, $RuntimeParameter)

        
        # Set the dynamic parameters' name
        $ParamName_datastore = 'Username'
        # Create the collection of attributes
        $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
        # Create and set the parameters' attributes
        $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
        $ParameterAttribute.Mandatory = $true
        # Add the attributes to the attributes collection
        $AttributeCollection.Add($ParameterAttribute)  
        # Generate and set the ValidateSet 
        $arrSet = (Get-ADUser -Filter *).name
        $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)
        # Add the ValidateSet to the attributes collection
        $AttributeCollection.Add($ValidateSetAttribute)
        # Create and return the dynamic parameter
        $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_datastore, [string], $AttributeCollection)
        $RuntimeParameterDictionary.Add($ParamName_datastore, $RuntimeParameter)
        return $RuntimeParameterDictionary
    }

    begin{
        $Group = $PsBoundParameters[$ParamName_portgroup]
        $username = $PsBoundParameters[$ParamName_datastore] 
    }
    process {
        if ($PSBoundParameters.ContainsKey('Credential')) {
            if ($Action -like "Add") {
                Add-ADGroupMember -Identity $group -Members $username -Credential $Credential
            } elseif ($Action -like "Remove") {
                Remove-ADGroupMember -Identity $group -Members $username -Credential $Credential
            } else {
                Get-ADGroupMember -Identity $group -Credential $Credential
            }
        } else {
            if ($Action -like "Add") {
                Add-ADGroupMember -Identity $group -Members $username
            } elseif ($Action -like "Remove") {
                Remove-ADGroupMember -Identity $group -Members $username
            } else {
                Get-ADGroupMember -Identity $group
            }
        }
    }
    end {
        if ($Output) {
            if ($PSBoundParameters.ContainsKey('Credential')) {
                Get-ADGroupMember -Identity $Group -Credential $Credential
            } else {
                Get-ADGroupMember -Identity $group
            }
        }
    }
}

Example 1

Set-SHDADGroupMemebers -Action Add -Group Administrators -Username Adam.Long -Output

Adds Adam.Long to the administrators group. Then it outputs all the users inside that group.

Example 2

Set-SHDADGroupMemebers -Action Remove -Group Administrators -Username Adam.Long

Removes Adam.Long from the Administrators group without outputting any additional information.