Tuesday, August 15, 2017

Powershell - Gather Mapped Drives from a List of Computer Names

I created the following Powershell script to gather remotely the mapped drives that users had in their profiles.  I had to create the script to gather the mapped drives from users that were not currently logged in.  The following script is what I came up with.

Sometimes the mappedDrivesInfo.txt file that is created is not copied from the remote device because the drive mapping was unsuccessful.  I separated the file collection portion from the main script and it worked flawlessly.




$ErrorActionPreference="SilentlyContinue"

$myCreds = Get-Credential -Credentail domain\localAdmin
Remove-PSDrive X -Force | Out-Null
Remove-PSDrive Y -Force | Out-Null
New-PSDrive -Name Y -PSProvider FileSystem -Root \\server\info | Out-Null
ForEach ($cName in Get-Content compList.txt) {
    Write-Host
    Write-Host "Connecting to: $cName"
    If (Test-Connection -ComputerName $cName -BufferSize 16 -Count 1 -ErrorAction 0 -Quiet) {
        Write-Host "Connection Successful"
        New-PSDrive -Name X -PSProvider FileSystem -Root \\$cName\c$ -Credential $myCreds | Out-Null
        $u = Get-WmiObject -Class Win32_UserProfile -ComputerName $cName -Credential $myCreds -Filter { SID like '%S-1-5-21-1793613773-621299329-1849977318%' }
        $LastUsers = $u | Sort-Object -Property LastUseTime -Descending 
        If ($LastUsers) {
            ForEach ($userAccount in $LastUsers) {
                $Loaded = $userAccount.Loaded
                # Covert the date to readable format
                $Script:Time = ([WMI]'').ConvertToDateTime($userAccount.LastUseTime)
                $Script:UserSID = New-Object System.Security.Principal.SecurityIdentifier($userAccount.SID)
                $User = $Script:UserSID.Translate([System.Security.Principal.NTAccount])
                $uName = $User -replace "DOMAIN\\", ""
                Write "Found user profile for: $User Last Logon: $Script:Time SID: $Script:UserSID ComputerName: $cName"
                Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList "powershell.exe -WindowStyle Hidden -NonInteractive -c Get-ChildItem -Path Microsoft.Powershell.Core\Registry::HKEY_USERS\$Script:UserSID\Network\ | Get-ItemProperty -Name RemotePath | Format-Table PSChildName, RemotePath -Wrap > c:\users\$cName-$uName-mappedDrivesInfo.txt"  -ComputerName $cName -Credential $myCreds | Out-Null
            } 
        }
        Start-Sleep -Seconds 5
        $mappedFiles = Get-ChildItem -Filter *mappedDrivesInfo.txt -File X:\Users
        ForEach ($mFile in $mappedFiles) {
            Write-Host "Found the following mapped drive file: $mFile"
            If ($mFile.Length -gt 0) {
                cp X:\users\$mFile Y:\$mFile
                Write-Host "Copied the above file."
            }
            Else {
                Write-Host "File is empty.  Did not copy it."
            }
        }
        Remove-PSDrive X -Force | Out-Null
    
    }
    Else {
        Write-Host "Unable to connect to $cName"
    }
}
Remove-PSDrive Y -Force | Out-Null



Powershell - Create Self-Signed Certificates (Automated Method)

Recently I needed to create a powershell script to generate a Root CA and a series of certificates that tied to the Root CA.  This is a script that I created to help automate  the process. 




# Powershell Script to assist in Creating Self-Signed Certificates 
# Must be executed with Administrative Permissions to Create the Certificates for the Local Machine

function Select-RootCert
{

    Write-Host
    Write-Host "Certificates Installed under the Local Machine on your Personal Store"
    $count = 0
    ForEach ($cert in Get-ChildItem Cert:\LocalMachine\My)
    {
        $count += 1
        Write-Host $count - $cert.Subject
    }
    $selectedRoot = Read-Host "Select"
    if ([int]$selectedRoot -le $count) {
       $count = 0
        ForEach ($cert in Get-ChildItem Cert:\LocalMachine\My)
        {
            $count += 1
            if ($count -eq [int]$selectedRoot) { return $cert.Thumbprint }
        } 
    } 
    else {
        Write-Host "Invalid Selection for the Root Certificate"
    }

    return "0"
}

function Generate-RootCert
{
    # This function generates the root certificate and places it in LocalMachine\Personal Folder
    $subjectCert = Read-Host "What would you like as the Subject of the certificate (Generated Root CA)"
    if ($subjectCert -eq "") { $subjectCert = "Generated Root CA" }
    Write-Host
    Write-Host "What is the duration of time to set for the certificate?"
    Write-Host "1. 12 Months"
    Write-Host "2. 24 Months"
    Write-Host "3. 36 Months (Default)"
    $timeInput = Read-Host "Duration (3)"
    if ($timeInput -eq "1") { $timeSelected = 12 }
    elseif ($timeInput -eq "2") { $timeSelected = 24 }
    else { $timeSelected = 36 }
    # Generate a RSA2048 Self-Signed Certificate
    $newRootCA = New-SelfSignedCertificate -Subject $subjectCert -CertStoreLocation Cert:\LocalMachine\My  -NotAfter (Get-Date).AddMonths($timeSelected) 
    # CertStoreLocation - Location is on the Local Machine in the Personal Certificates Folder
    # KeyUsage - Allows the key to be used to sign other keys
    # NotAfter - Sets the Time Duration that the Certificate is Valid for...
    Write-Host
    Write-Host "Unless an error is displayed above the certificate was created successfully.  You can view the new Root CA"
    Write-Host "through the MMC snap-in for the Local Computer Certificates under the Personal Certificates."
    Write-Host
    Return $newRootCA.Thumbprint
}

function Create-ServerCert ([String]$Thumbprint)
{
    Write-Host
    $serverName = Read-Host "What is the Server Name of the Server? "
    $domainName = Read-Host "What is the Domain Name of the Server? "
    $serverName = $serverName.ToUpper()
    $serverName = "$serverName.$domainName"
    Write-Host $serverName
    if ($serverName) {
        Write-Host
        Write-Host
        Write-Host "What is the duration of time to set for the certificate?"
        Write-Host "1. 12 Months"
        Write-Host "2. 24 Months"
        Write-Host "3. 36 Months (Default)"
        $timeInput = Read-Host "Duration (3)"
        if ($timeInput -eq "1") { $timeSelected = 12 }
        elseif ($timeInput -eq "2") { $timeSelected = 24 }
        else { $timeSelected = 36 }
        Write-Host
        $addResponse = Read-Host "Specify additional FQDN or DNS entries for certificate (No is default)"
        if (($addResponse -eq "Yes") -or ($addResponse -eq "yes") -or ($addResponse -eq "y")) {
            $addNames = Read-Host "Additional FQDN or DNS entries seperated with a comma"
            $dnsNames = "$serverName, $addNames"
        }
        else {
            $dnsNames = $serverName
        }
        # Get the Generated Root CA's thumbprint that we generated
        $rootCA = (Get-ChildItem -Path Cert:\LocalMachine\My\$Thumbprint)
        New-SelfSignedCertificate -KeyExportPolicy Exportable -Subject "CN=$serverName" -DnsName $dnsNames -CertStoreLocation Cert:\LocalMachine\My -NotAfter (Get-Date).AddMonths($timeSelected) -Signer $rootCA -KeySpec KeyExchange -KeyUsageProperty All
    }
    else {
        Write-Host "The FQDN of the Server needs to be Specified"
        Write-Host
    }
}

function Show-Menu
{
    $input = "a"
    $rootCAThumbprint = "0"
    do
    {
        Write-Host
        Write-Host "===Self-Signed Certificate Management==="
        Write-Host
        Write-Host "1. Generate Root Certificate"
        Write-Host "2. Select Root Certificate to Use"
        Write-Host "3. Create Server or Client Certificate(s) with Root Certificate"
        Write-Host
        if ($rootCAThumbprint -ne "0") {
            Write-Host "Selected Root Certificate is:"
            $currentCert = Get-ChildItem Cert:\LocalMachine\my | Where-Object {$_.Thumbprint -eq $rootCAThumbprint }
            Write-Host Subject: $currentCert.Subject
            Write-Host Thumbprint: $currentCert.Thumbprint
            Write-Host
        }
        Write-Host "Q. Quit"
        $input = Read-Host "Selection: "
        switch ($input)
        {
            '1' {
                    Write-Host
                    $rootCAThumbprint = Generate-RootCert
                    Write-Host
                }
            '2' {
                    Write-Host
                    $rootCAThumbprint = Select-RootCert
                    Write-Host
                }
            '3' {
                    Write-Host
                    if ($rootCAThumbprint -ne "0") {
                        Create-ServerCert -Thumbprint $rootCAThumbprint
                    }
                    else {
                        Write-Host
                        Write-Host "No Root CA has been generated or selected." -ForegroundColor Red
                        Write-Host
                    }
                    Write-Host
                }
        }
    } until (($input -eq 'q') -or ($input -eq 'Q'))
}


Show-Menu


Saturday, February 11, 2017

Powershell - Uninstall Packages Remotely

Recently I have been contemplating how I could more efficiently uninstall or view packages that a user has installed on their computer and then uninstall those packages remotely without having to take the time of the user to do so through a remote interactive session.  


I have written the below Powershell script which will prompt you for the computers name or IP Address that you are working with.  Then it will display the installed programs (Notice in the script you can filter by a package name like Java).  Then you can call the package or packages you would like to uninstall by its name.  If your user account is recognized as a local administrator on the computer you should not have an issue.  It does allow you to use other credentials if necessary.



#Powershell program to remove packages that are specified by the user

function remove-Package($package, $compName, $credName) {
    If ($credName -eq $env:USERNAME) {
        $s = Get-WmiObject -Class Win32_Product -ComputerName $compName | Where-Object { $_.Name -match $package }
    }
    Else {
        $s = Get-WmiObject -Class Win32_Product -ComputerName $compName -Credential $credName | Where-Object { $_.Name -match $package }
    }
    If ($s) {
        Write $s | Format-Table Name, Version, IdentifyingNumber
        $uninstallPrompt = Read-Host -Prompt "Uninstall the above package(s) (y/n)"
        If ($uninstallPrompt -eq "Y" -or $uninstallPrompt -eq "y") {
            $s.Uninstall()
        }
        Else {
            Write "Aborted uninstall..."
        }
    }
    Else {
        Write "Error uninstalling $package"
    }
}

# Remote Computer Selection or . for localhost
Write ""
Write "This program is designed to display a list of applications on a computer,"
Write "allow you to choose which one to uninstall, and then uninstall it without"
Write "having to interact with the user."
Write ""
$cName = Read-Host -Prompt "Target Computer Name or IP Address (. for localhost)"
$uPrompt = Read-Host -Prompt "Use your account to connect to remote computer (y/n)"
If ($uPrompt -eq "Y" -or $uName -eq "y") { 
    $uName -eq $env:USERNAME 
}
Else {
    $uName = Read-Host -Prompt "Enter Username to Use" 
}

# List all packages on the computer
If ($uName -eq $env:USERNAME) {
    #$all = Get-WmiObject -Class Win32_Product -Filter "Name LIKE '%Java%'"
    $all = Get-WmiObject -Class Win32_Product -ComputerName $cName
}
Else {
    #$all = Get-WmiObject -Class Win32_Product -Filter "Name LIKE '%Java%'"
    $all = Get-WmiObject -Class Win32_Product -ComputerName $cName -Credential $uName
}
If ($all) {
    Write $all | Sort Name, Version | Format-Table Name, Version
    Write ""
    $userInput = Read-Host -Prompt "Uninstall a Package Listed Above (y/n)"

    DO
    {

        If ($userInput -eq "Y" -or $userInput -eq "y") {
            $packageInput = Read-Host -Prompt "Copy or Type the Name of the Package as shown above to Uninstall"
            remove-Package -package $packageInput -compName $cName -credName $uName
        }

        If ($userInput -eq "Y" -or $userInput -eq "y") {
            $userInput = Read-Host -Prompt "Uninstall another Package (y/n)"
        }

    } While ($userInput -eq "Y" -or $userInput -eq "y")
}


f


Powershell - Gather Mapped Drives from a List of Computer Names

I created the following Powershell script to gather remotely the mapped drives that users had in their profiles.  I had to create the script...