Jump to content
*Coming November/December* Signature Rigs & Content Embed Wizard (Google Docs,Soundcloud,Spotify & More) ×
*Coming December* EHW Marketplace ×

Welcome to ExtremeHW

Welcome to ExtremeHW, like most online communities you must register to view or post in our community, but don't worry this is a simple free process that requires minimal information for you to signup. Be a part of ExtremeHW by signing in or creating an account.

  • Start new topics and reply to others
  • Subscribe to topics and forums to get email updates
  • Get your own profile page and make new friends
  • Send personal messages to other members.
  • Take advantage of site exclusive features.

KSIMP88's PowerShell Tips and Tricks


Recommended Posts

I'll be using this post to provide tips and tricks I've learned with PowerShell. I keep most of my stuff at work, so perhaps tomorrow I'll bring some content to this post after I scrub my scripts of anything specific to our organization. I'll start with a few simple ones. Yes, these can be done with other methods, such as .bat files, or python, what have you, but I use PowerShell, and it's what I know. I'll be writing descriptions below, scripts to follow. Feel free to request scripts! I enjoy doing this, and it's good for job security. I'll likely even be updating scripts on here as well, as I learn of better ways to run them. For example, I'm building the driver update script as I write this post, but the one I wrote at work is much nicer, so I'll be replacing it with bits from that one.

 

A couple of quick things I want to mention.

 

Functions are basically meant to be scripts you can cache in your PowerShell profile, and allow passing variables in-line. I typically work with functions, but sometimes it doesn't quite fit the plan. Really, it depends on your tastes. 

When you see $, that means it's defining a string as a variable. 

When you see # at the beginning of a line, that code is disabled, or it is meant as a way of putting notes in the script. Nothing that follows a # in-line will run in a PowerShell script.

 

Function Template

For those interested in creating there own PowerShell functions, this is a template I use.

Spoiler

function FUNCTION-NAME {

[cmdletbinding()]

param (

    [parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True,Position=0)]
    [Alias('PSComputerName','DNSHostName','CN','Hostname')]

    [string]
    $ComputerName = $env:COMPUTERNAME

    #### INSERT ANY ADDITIONAL PARAMETERS HERE
    
) #param

$ComputerName | ForEach-Object {

    if (Test-Connection -ComputerName $ComputerName -Count 1 -Quiet)
        {

        #### INSERT YOUR SCRIPT HERE
        
        } # Offline Check

    else 
        { 
            Write-Host "Computer is Unreachable or Offline" -ForegroundColor Gray 
        }    
} # Foreach

} #Function

 

 

Installing Windows Updates

Some of us don't like automatic updates. Guess what? You always had the power, with PowerShell, to control it. We simply disable the update services, and add some scheduled tasks to keep that service disabled, and only download the updates we want, and use a simple script to install them manually, or we could add the script as a scheduled task to automatically install anything we download to a specific folder, we can even add checks to see if it's been installed, and then delete source files to save space.

CODE:

Spoiler


## Installs all MS Update .msp and .msu files in C:\Offlineupdates. 
## Only updates that apply to the system will run, and others will be skipped, so there should be no issue with mixed updates. 

function Install-MSUpdates {

[cmdletbinding()]

param (

    [parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True,Position=0)]
    [Alias('PSComputerName','DNSHostName','CN','Hostname')]
      
      [string]
      $ComputerName = $env:COMPUTERNAME,

      [switch]
      $RunMRT = $False,
     
      [string]
      $Restart1 = 'Security updates are currently being applied. These updates are required. Once complete, you will be notified of a required restart.',

      [string]
      $Restart2 = 'Your system will reboot in 5 minutes. Please save any work.',
            
      [string]
      $UpdatesPath = 'c:\OfflineUpdates',

      [string]
      $NotifySystem = 'Security updates are required for this system. Please call the help desk to remedy once the system is connected via hardline, or bring the system in.',
               
      [string]
      $RemoteStagingPath = '\\' + $ComputerName + '\C$\TEMP'

) # param

$ComputerName | ForEach-Object {

        if (Test-Connection -ComputerName $ComputerName -Count 1 -Quiet)
        {

        Start-Transcript -Path \\$ComputerName\C$\TEMP\InstallLogs\ManualMSUpdates.txt
                           
                            {
                               
                                New-Item -ItemType Directory $RemoteStagingPath\OfflineUpdates -ErrorAction SilentlyContinue | Out-Null
                                Write-Host "Copying most recent updates to $RemoteStagingPath. This will take some time."
                                Robocopy $UpdatesPath $RemoteStagingPath\OfflineUpdates /e /mt /np /nfl /ndl /njh /njs /ns /nc /r:5

                            }
                                                                                            
                            Write-Host "Installing Updates now, this will take some time"
                            Invoke-WmiMethod -ComputerName $ComputerName -Path Win32_Process -Name Create -ArgumentList "msg * $Restart1" | Out-Null
                            
                            Write-Host "Installing Office EXE's"                                                                                          
                            Invoke-Command -ComputerName $ComputerName -ScriptBlock {
                            
                                $UpdateExes = (Get-ChildItem "$RemoteStagingPath\OfflineUpdates\05_OfficeUpdates" -Recurse | Where-Object {$_.Extension -eq '.exe'})

                                foreach ($UpdateExe in $UpdateExes)
                                    { 
                                        $UpdateExeInstall = $UpdateExe.fullname
                                        Start-Process powershell -ArgumentList ("$UpdateExeInstall", '/passive', '/quiet', '/norestart') -Wait 
                                    }
                            
                                }

                            if ($RunMrt -eq $True)

                                {

                                    Write-Host "Running Malicious software removal tool" 
                                                                                                                         
                                        Invoke-Command -ComputerName $ComputerName -ScriptBlock {
                            
                                            $UpdateMSRs = (Get-ChildItem "$RemoteStagingPath\OfflineUpdates\06_Malicious_Software_Removal" -Recurse | Where-Object {$_.Extension -eq '.exe'})

                                            foreach ($UpdateMSR in $UpdateMSRs)
                                                { 
                                                    $UpdateMSRInstall = $UpdateMSR.fullname
                                                    Start-Process powershell -ArgumentList ("$UpdateMSRInstall", '/quiet', '/F:Y') -Wait 
                                                }
                            
                                            }
                                }

                            else {}

                            Write-Host "Installing MSU's"
                            Invoke-CommandAs -ComputerName $ComputerName -ScriptBlock {
                                
                                $UpdateMsus = (Get-ChildItem "$RemoteStagingPath\OfflineUpdates\" -Recurse | Where-Object {$_.Extension -eq '.msu'})

                                foreach ($UpdateMsu in $UpdateMsus)
                                    {   
                                        $UpdateMsuInstall = $UpdateMsu.fullname
                                        Start-Process -FilePath 'C:\windows\SysWOW64\wusa.exe' -ArgumentList ("$UpdateMsuInstall", '/quiet', '/norestart') -Wait 
                                    } 
 
                                } -AsSystem

                            Write-Host "Installing CAB's"
                            Invoke-CommandAs -ComputerName $ComputerName -ScriptBlock {
                                                            
                                $UpdateCabs = (Get-ChildItem "$RemoteStagingPath\OfflineUpdates\" -Recurse | Where-Object {$_.Extension -eq '.cab'})

                                foreach ($UpdateCab in $UpdateCabs)
                                    { 
                                        $UpdateCabInstall = $UpdateCab.fullname
                                        Start-Process -FilePath 'C:\windows\SysWOW64\dism.exe' -ArgumentList ('/Online', '/Add-Package', "/PackagePath:$UpdateCabInstall", '/norestart') -Wait 
                                    }
                                    
                                
                                } -AsSystem

                            Invoke-WmiMethod -ComputerName $ComputerName -Path Win32_Process -Name Create -ArgumentList "msg * $Restart2" | Out-Null
                            Start-Sleep -Seconds 300
                            Write-Host "Rebooting Now"

                            Stop-Transcript

                            Restart-Computer -ComputerName $ComputerName -Force
                                                            
                        
                                                
    

        }
        else 
        { 
            Write-Host "$ComputerName is Unreachable or Offline" -ForegroundColor Gray 
        }    
} # Foreach
} # fuction

DESCRIPTION

Spoiler

This will force any driver installs. Notice the MSR is turned off by default, and has a specific folder. I organized my folder with the last folder being the cumulative, then forcing a restart, with high success. At some point in the future, I'll go over keeping the automatic update service stopped.

The variables in blue should change based on your needs. You man see where in the script the Restart messages are. The UpdatesPath is the location where the update files are staged, and the RemoteStagingPath is where you would like to send them. This is really useful if running over a network, notice the $ComputerName variable.

Basically, when you copy this into PowerShell, you run the function like most, defining the computer you wish to run the updates on. For example, "Install-MSUpdates -ComputerName Server02"

Forcing Drivers

Sometimes a device is not officially supported by Windows 10, and if you just download and try to run the .exe, Windows tells you to get rekkd. We had this happen a lot with old printers, so I learned how to use the PnP Utility. I needed to do this for my old Alienware 17 R2 (2015),  as the drivers from dell were causing USB glitches. I downloaded the H87 chipset drivers directly from Intel, and had to force them with this method, and the issues went away!

## This will use the PnP Utility to attempt to force drivers on a system.

Function Update-Drivers {

$SourceFiles = Read-Host "Where are the drivers staged? (ex c:\drivers\Audio)"
Get-ChildItem "$SourceFiles" -Recurse -Filter "*.inf" | ForEach-Object { PNPUtil.exe /add-driver $_.FullName /install }

}
Spoiler

First, we need to download our drivers. Luckily, I have a great test I can run, a new chipset driver came out for my board. Sure, it will work with normal methods, but I'll use it as proof of concept.

Once you download your drivers, extract the files. I extracted them to C:\Drivers. Sometimes you download a .zip, extract it, and there's a .exe file. Guess what? Extract it. You can use 7-zip or WinZip, right click the .exe and extract it. 
The AMD chipset drivers this time were a little bit of a pain, I found where the actual drivers were placed with the self-extractor, so I'll use that. 
C:\AMD\Chipset_Driver_Installer\AMD_Chipset_Drivers\AMD_Chipset_Drivers 
There was a file called Data1.cab. That's where the .inf files I was looking for were, and that's all I need. So now I have the files in C:\Driversdriverfiles.thumb.png.23424414ff59ff9cff575de1e14eabec.png

Now that my drivers are staged, I can run the script. PowerShell should be opened as admin.

First, we see that when you run the script, it stores what's called a function in your PowerShell session, so you can simply call on the function repeatedly if needed, without having to write or paste the entire script again. I'll go into PowerShell profiles at some point to show how you can keep all functions available every time you open PowerShell.
Next, I call the function. It asked where the files are, so I input C:\Drivers, and the PnP Toolkit installed all I needed, without extra garbage! Clean drivers, less crap. Some weren't required, so they didn't all install. But there you have it! Fun fact, the entirety of the actual files I needed for the chipset was less than 6 MB.

driverscript.thumb.png.cf12d75a16015f0a5b04cf81f67f16ab.png

 

 

 

Backup Profile

Simple scripts can really make backing up your profile a breeze. Especially with us overclockers, who tend to break their systems! While it could be argued that you can simple have your profile run off your cloud storage, or another hard drive other than the OS drive, this backup does make it easy to quickly move the profile to another device.

script coming very soon

 

Remove User Profile

Sometimes you want to remove profiles from a system. There are many ways to do this, but the following script is best in a network environment. This script I developed a while back, and for almost each line of code, I gave a description as to what is happening for each part. Take a look, it does a very good job of properly removing user profiles from a target system.

CODE:

Spoiler

## This script will remove a user account on a given computer

# Clarifies use of script
Write-Host "This script will not remove an account from Active Directory. It will only remove the account from the specific machine. Use for troubleshooting corrupt accounts. This should not be run on the target system; this is intended to be run remotely. Make sure the user is logged out."
Write-Host " "

# Prompts for computer name
$ComputerName=Read-Host "Please provide computer name or IP"

# Checks existing profiles on system
$SourceProfiles="\\$ComputerName\c$\users"
Get-ChildItem $SourceProfiles -name

# Prompts user to choose profile to delete
$user=Read-Host "Please input user profile to delete"

# Deletes chosen profile on given computer
$Confirmation = Read-Host "Are you sure? This will DELETE the user profile, and all that user's data. Confirm by typing DELETE."

if ($Confirmation -eq "DELETE") {
Get-CimInstance -Class Win32_UserProfile -ComputerName $ComputerName | Where-Object { $_.LocalPath.split('\')[-1] -eq "$user"} | Remove-CimInstance
} else
{ Write-Host "not confirmed, canceling" }

 

Software Installs

I'll just post a single install for this, unless someone requests more. Basically, in an Enterprise environment, you may find that there are times where Enterprise Management suites don't always work as intended. A simple script could be called on to install software that is on a network share, and you can even use the repository to compare versions, without ever having to update your script! I'm working on Invoke-WebRequest commands to figure out how to do this directly with developers, but for now, it relies on someone simply updating the installer on the network drive.

Spoiler




function Install-MicrosoftEdgeVerTest {

[cmdletbinding()]

param (

      [parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
      [Alias('PSComputerName','DNSHostName','CN','Hostname')]

      [string]
      $ComputerName = $env:COMPUTERNAME,

      [string]
      $EdgePath = 'c:\ProgramInstalls\Microsoft\Edge\*',

      [string]
      $RemoteStagingPath = '\\' + $ComputerName + '\C$\TEMP'

) # param

if (Test-Connection -ComputerName $ComputerName -Count 1 -Quiet)
{
    c:\ProgramInstalls\Get-MSIDatabaseProperties.ps1'
    
    $EdgeInstallFile = (Get-ChildItem "$EdgePath.msi").FullName

    $EdgeCurrentVersion = [version](Get-MSIDatabaseProperties $EdgeInstallFile).ProductVersion

    Remove-Item $RemoteStagingPath\Microsoft -Recurse -Force -ErrorAction SilentlyContinue

    New-Item -ItemType Directory -Path "$RemoteStagingPath\InstallLogs" -ErrorAction SilentlyContinue | Out-Null

    Start-Transcript -Path "$RemoteStagingPath\InstallLogs\Edge_Update_$EdgeCurrentVersion.txt" | Out-Null
    
    Write-Host "Gathering Microsoft Edge for Business installation information for $ComputerName..."

    $InstallList = (Invoke-Command -ComputerName $ComputerName -ScriptBlock { Get-ItemProperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* , HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* })
    $EdgeInstalled = if ($InstallList | Where-Object { $_.displayname -eq "Microsoft Edge"}) {$true} else {$false}
                    
    if ( $EdgeInstalled -eq $true )              
    { 
        Write-Host "Microsoft Edge for Business is installed, checking version..." -ForegroundColor Yellow
                
        $EdgePatched = if (($InstallList | Where-Object { $_.displayname -eq "Microsoft Edge" }).displayversion -eq $EdgeCurrentVersion) {$true} else {$false}

        if ( $EdgePatched -eq $true )
        {
            Write-Host "Microsoft Edge for Business is installed and updated" -ForegroundColor Green
        }
                
        elseif ( $EdgePatched -eq $false )
        {
                Write-Host "Microsoft Edge for Business is not updated to the current version. Installing patch $EdgeCurrentVersion" -ForegroundColor Yellow

                if ((Test-Path "\\$ComputerName\c$\TEMP\Microsoft\Edge\Edge_$EdgeCurrentVersion.msi") -eq $false)
                {
                    New-Item -ItemType Directory $RemoteStagingPath\Microsoft\Edge -ErrorAction SilentlyContinue | Out-Null
                    Write-Verbose "Copying Files to install $RemoteStagingPath"
                    Copy-Item $EdgePath $RemoteStagingPath\Microsoft\Edge -Recurse -Force 
                }
                
                elseif ((Test-Path "\\$ComputerName\c$\TEMPInstall\Microsoft\Edge\Edge_$EdgeCurrentVersion.msi") -eq $true) 
                {
                    Write-Verbose "Update File already copied to Download path" 
                }
                
                Write-Verbose "Files copied to TEMPInstall folder"

                Invoke-Command -ComputerName $ComputerName -ScriptBlock { Start-Process msiexec.exe -Wait -ArgumentList $args } -ArgumentList "/i C:\TEMP\Microsoft\Edge\Edge_$EdgeCurrentVersion.msi /qn"

                Start-Sleep -Seconds 10
                
                #Check if Microsoft Edge for Business is installed after install attempt
                if ((Get-Item "\\$ComputerName\c$\Program Files (x86)\Microsoft\Edge\Application\msedge.exe").VersionInfo.FileVersion -like $EdgeCurrentVersion)
                { 
                    Write-Host "Microsoft Edge for Business $EdgeCurrentVersion has been successfully installed" -ForegroundColor Green
                } 

                else 
                { 
                    Write-Host "Microsoft Edge for Business $EdgeCurrentVersion failed to install" -ForegroundColor Red 
                }  

            } #Edge Patched 
                       
      } #Edge already installed
            
      elseif ( $EdgeInstalled -eq $false )
      {     
            Write-Host "Microsoft Edge for Business is not installed on $ComputerName, installing..." -ForegroundColor Yellow
                  
            if ((Test-Path "\\$ComputerName\TEMP\Microsoft\Edge\Edge_$EdgeCurrentVersion.msi") -eq $false) 
            {
                New-Item -ItemType Directory $RemoteStagingPath\Microsoft\Edge -ErrorAction SilentlyContinue | Out-Null
                Write-Verbose "Copying Files to install $RemoteStagingPath"
                Copy-Item $EdgePath $RemoteStagingPath\Microsoft\Edge -Recurse -Force 
            }
                  
            else 
            {
                Write-Verbose "Files already copied to Download path" 
            }

            Write-Verbose "Files copied to TEMPInstall folder"

            Write-Verbose "Installing Microsoft Edge for Business $EdgeCurrentVersion on $ComputerName"

            Invoke-Command -ComputerName $ComputerName -ScriptBlock { Start-Process msiexec.exe -Wait -ArgumentList $args } -ArgumentList "/i C:\TEMP\Microsoft\Edge\Edge_$EdgeCurrentVersion.msi /qn"

            Start-Sleep -Seconds 10
                        
            #Check if Microsoft Edge for Business is installed after install attempt
            if ((Get-Item "\\$ComputerName\c$\Program Files (x86)\Microsoft\Edge\Application\msedge.exe").VersionInfo.FileVersion -like $EdgeCurrentVersion)
            { 
                Write-Host "Microsoft Edge for Business $EdgeCurrentVersion has been successfully installed" -ForegroundColor Green
            } 
            
            else 
            { 
                Write-Host "Microsoft Edge for Business $EdgeCurrentVersion failed to install" -ForegroundColor Red 
            }   
      } # End Edge Install

      Remove-Item "\\$ComputerName\c$\Users\Public\Desktop\Microsoft Edge.lnk" -Force -ErrorAction SilentlyContinue

      Stop-Transcript

} # Offline Check

else 
{ 
      Write-Host "Computer is Unreachable or Offline" -ForegroundColor Gray 
}    

} #Function

This looks at the Edge .msi, and compares it to the version on the system. It's dependent on a script I do not own, called get-msidatabaseproperties.

 

 

Edited by KSIMP88
Link to post
Share on other sites
28 minutes ago, The Pook said:

first thing you should do on any install is disable AeroShake :D

 

doesn't have to be done through PowerShell but it can 

Pook holy hell. I've been trying to word what has been going on, I thought it was a glitch. Holy crap it's a freaking feature? I feel like such a moron. ITS BEEN SO MANY YESRS ARGGGGHHHHH I love u

Link to post
Share on other sites

Small suggestion for those not familiar to command type interfaces like powershell, it may help readers if you highlight the variables that users need to change applicable to their systems in another colour. I find this can really help the uninitiated.

 

Only a suggestion, don't feel like you need to :)

 

Link to post
Share on other sites

No, that's a good suggestion. I plan to keep improving this, it's quite a project. Unfortunately I don't have as much free time as I'd like, and I can't dedicate 100% of it to this, but I'll be working on it!

Link to post
Share on other sites
7 hours ago, KSIMP88 said:

No, that's a good suggestion. I plan to keep improving this, it's quite a project. Unfortunately I don't have as much free time as I'd like, and I can't dedicate 100% of it to this, but I'll be working on it!

Rome wasn't built in a day :)

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

This Website may place and access certain Cookies on your computer. ExtremeHW uses Cookies to improve your experience of using the Website and to improve our range of products and services. ExtremeHW has carefully chosen these Cookies and has taken steps to ensure that your privacy is protected and respected at all times. All Cookies used by this Website are used in accordance with current UK and EU Cookie Law. For more information please see our Privacy Policy