Scripting, System Center, Technology, windows

Thank you, PowerShell!


These are just a few snippets of PowerShell code that helped me out during the past week. There were quite a few others, but these were the easiest examples to show.

UPDATE 1 – Swapped-out Invoke-WebRequest with System.Net.WebClient/DownloadFile in the download script example below, per suggestion of Guy Leech (thanks!)

Adding a User Login to SQL Server

This example adds a domain computer account to a SQL Server instance with “sysadmin” role membership. This example requires the dbatools PowerShell module.

$computer = 'db02'
$account = 'contoso\cm01$'
New-DbaLogin -SqlInstance $computer -Login $account
Get-DbaLogin -SqlInstance $computer -Login $account | Set-DbaLogin -AddRole sysadmin

Adding an Account to a remote Server Administrators Group with Service Logon Rights

This example adds a domain user/service account into the local Administrators group on a remote server, and grants permissions for it to “login as a service” and “logon as a batch”. This could have been accomplished via GPO, but for various reasons that was not an option. This example requires the carbon PowerShell module.

$computer = 'db02'
$account = 'contoso\cm-sql'

$s1 = New-PSSession -ComputerName $computer -Name 's1'
Enter-PSSession -Session $s1
Add-LocalGroupMember -Group 'Administrators' -Member $account
Grant-CPrivilege -Identity $account -Privilege 'SeBatchLogonRight','SeServiceLogonRight'
Exit-PSSession

Creating a Shared Folder Tree

This is basically a template for establishing a “Definitive Source Library”, or centralized content store for things like applications, drivers, scripts, utilities, and so on.

It creates a root-level folder “Sources” on a selected logical drive, sharing it as “Sources$” (hidden share), and then creating more sub-folders below that. The folder structure can be defined in a data file, a GitHub Gist, an explicit variable, or just about anything you prefer. In this example, we used a .txt file.

Example: folders.txt

Apps\7-zip
Apps\Google\Chrome
Apps\Microsoft\O365ProPlus
Apps\Mozilla\Firefox
Apps\Notepad++
Apps\VLC
Certs
DrvPkg
DrvSrc
OSImages
Scripts\ConfigMgr
Scripts\WSUS
Scripts\SQL
Tools

Example: script code… (be sure to change the $DriveLetter assignment to suit your needs)

[CmdletBinding()]
param (
  [parameter()][ValidateLength(1,1)][string] $DriveLetter = "E",
  [parameter()][ValidateNotNullOrEmpty()][string]$InputFile = ".\folders.txt",
  [parameter()][ValidateNotNullOrEmpty()][string]$RootFolder = "SOURCES"
)
$ErrorActionPreference = 'stop'
try {
    $rootPath = "$DriveLetter`:\$RootFolder"
    if (!(Test-Path $rootPath)) { 
        mkdir $rootPath -Force 
        Write-Verbose "created folder: $rootPath"
    }
    $folders = Get-Content $InputFile
    foreach ($folder in $folders) {
        $fpath = Join-Path -Path $rootPath -ChildPath $folder
        if (!(Test-Path $fpath)) {
            mkdir $fpath -Force 
            Write-Verbose "created folder: $fpath"
        }
        else {
            Write-Verbose "folder exists: $fpath"
        }
    }
    $shareName = "$RootFolder`$"
    if ($shareName -notin (Get-SmbShare).Name) {
        Write-Verbose "creating share: $shareName"
        New-SmbShare -Path $rootPath -Name "$shareName"
    }
    Write-Host "finished processing"
}
catch {
    Write-Error $_.Exception.Message
}

Downloading Sample Applications

This example downloads installer files directly from vendor web or FTP sites into the appropriate (directed) local folders (which were created by the preceding example). This also uses a data file to specify the folder path and the associated remote URL path. It’s worth noting that I chose a tilde “~” character delimiter to distinguish from the embedded “=” characters in the URL strings, but you could make this a .csv file and wrap the values in double-quotes (e.g. “http://blahblahblahblah&locale=en-us”)

Example: downloads.txt

Apps\7-Zip~https://www.7-zip.org/a/7z1900-x64.msi
Apps\Mozilla\Firefox~https://download-installer.cdn.mozilla.net/pub/firefox/releases/70.0/win64/en-US/Firefox%20Setup%2070.0.msi
Apps\Google\Chrome~https://dl.google.com/tag/s/dl/chrome/install/googlechromestandaloneenterprise64.msi
Apps\Notepad++~http://download.notepad-plus-plus.org/repository/7.x/7.8/npp.7.8.Installer.x64.exe
Apps\VLC~https://ftp.osuosl.org/pub/videolan/vlc/3.0.8/win64/vlc-3.0.8-win64.exe

Bonus: additional downloads.txt entries to include SCConfigMgr’s Modern Driver Management tools, Ola Hallengren’s maintenance script, Bryan Dam’s WSUS ass-whoopin script, and positive vibes. 🙂

Scripts\WSUS~https://damgoodadmin.com/download/invoke-dgasoftwareupdatemaintenance/?wpdmdl=326&refresh=5db464511e44c1572103249~Invoke-DgaSoftwareUpdateMaintenance.zip
Tools\DriverAutomationTool~https://gallery.technet.microsoft.com/Driver-Tool-Automate-9ddcc010/file/224244/1/Driver%20Automation%20Tool.zip
Tools\ConfigMgrWebService~https://gallery.technet.microsoft.com/ConfigMgr-WebService-100-572825b2/file/223724/1/ConfigMgr%20WebService%201.8.0.zip
Tools\ConfigMgrWebService~https://raw.githubusercontent.com/SCConfigMgr/ConfigMgr/master/Operating%20System%20Deployment/Drivers/Invoke-CMApplyDriverPackage.ps1
Tools\SQL~https://ola.hallengren.com/scripts/MaintenanceSolution.sql

Example: script code

[CmdletBinding()]
param(
    [parameter()][ValidateNotNullOrEmpty()][string]$InputFile = ".\downloads.txt",
    [parameter()][ValidateNotNullOrEmpty()][string]$rootPath = "H:\SOURCES"
)
try {
    $apps = Get-Content $InputFile
    foreach ($app in $apps) {
        $appdata   = $app -split '~'
        $appPath   = $appdata[0]
        $appSource = $appdata[1]
        if ($appdata.Count -eq 3) {
            $filename = $appdata[2]
        }
        else {
            $filename  = $($appSource -split '/' | select -Last 1) -replace '%20','_'
        }
        $destPath  = Join-Path -Path $rootPath -ChildPath $appPath
        if (!(Test-Path $destPath)) { 
            mkdir $destPath -Force 
            Write-Verbose "created folder: $destPath"
        }
        $destination = Join-Path -Path $destPath -ChildPath "$filename"
        if (!(Test-Path $destination)) {
            # Invoke-WebRequest -Uri $appSource -OutFile $destination
            # modified per https://twitter.com/guyrleech
            [void](New-Object System.Net.WebClient).DownloadFile($appSource, $destination)
        }
        else {
            Write-Verbose "file exists: $destination"
        }
    }
    Write-Host "finished processing"
}
catch {
    Write-Error $_.Exception.Message 
}

Cheers!

Leave a comment