Link to home
Start Free TrialLog in
Avatar of Mike
MikeFlag for United States of America

asked on

Need Help crating powershell Install script

Greeting Experts -

Need help setting up a PowerShell script to install a piece of client software (WindowsSensor.exe) on the list of computers. Can somebody help me write a script that will prompt me for my Admin Credentials, copy the software from a file directory (source file) to folder on the local computer, and then start the install from the command line using these install arguments

software:  WindowsSensor.exe
CLI Install arguments:  WindowsSensor.exe /install /quiet /norestart CID=InstallToken
Avatar of Darrell Porter
Darrell Porter
Flag of United States of America image

param (
    [Parameter(Mandatory=$true)][string]$username,
    [Parameter(Mandatory=$true)][string]$password
)


#$machineArray = import-csv "d:\Files\ListOfComputers.csv"

$script = $MyInvocation.MyCommand.Definition
$scriptname = [io.path]::GetFileNameWithoutExtension($(Split-Path $script -Leaf))

$runlog = Get-Date -Format yyyyMMddHHmm
# If the folder for this script's logs doesn't exist, make it!
If (-not(Test-Path "D:\Logs\$Scriptname" -PathType Container)) { New-Item -ItemType directory -Path "D:\Logs\$Scriptname" }
$logfile = (-join("D:\Logs\\",$scriptname,"\\",$scriptname,"-",$runlog,".log"))
$nl = [Environment]::NewLine

$init = {

    function Do-Work ($machinename $username $password) {
        filter timestamp {"$(Get-Date -Format G): $_"}
        $runday = Get-Date -Format "yyyyMMddHHmm"
        # check if the store answers ping first
        $ans = Test-Connection -ComputerName $machinename -count 1 -quiet
  
        if ($ans) {
            Write-Output (('---------------------------------------')|timestamp)
            # Insert work here at 3 indentations (12 spaces) from Left margin
            $MachinePath = "\\$machinename\C$\Temp"
            $secCred = SecureCredentials $username $password
            New-PSDrive -Name TMP -PSProvider FileSystem -Root $MachinePath -Credential $secCred | Out-Null
            #Test drive map
            if (Test-Path -Path $MachinePath) {
                if (!(Test-Path -Path "$MachinePath\WindowsSensor.exe")) {
                    Log "Cannot locate WindowsSensor Installer on $machinename; cannot install WindowsSensor."
                    return $false
                }
                Else {
                    &$PathToPSExec.EXE -s \\$machinename C:\Temp\WindowsSensor.exe  /install /quiet /l*v:c:\temp\WindowsSensorMSIInstall.log /norestart CID=InstallToken 2>&1>C:\Temp\WindowsSensorPSExec.log
                }
            }
        }
        else {
            write-output ''
            write-output (('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')|timestamp)
            write-output (($machinename + ' offline!')|timestamp)
            write-output (('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')|timestamp)
            write-output ''
        }

        
    }

}


function ExitWithCode 
{
    param 
    ( 
        $exitcode 
    )

    $host.SetShouldExit($exitcode) 
    exit 
}

#

if (Test-Path $logfile) {
    Remove-Item $logfile
}

Remove-Job *

$queueLimit = 100
$counter = 0
$totalCycles = $storearray.count

foreach ($machine in $machinearray | Sort 'Machine Name') {
    $machinename = $machine.'Machine Name'
    $counter += 1
    write-host "Processing cycle $counter out of $totalCycles" -ForegroundColor Green
    $running = @(Get-Job | Where-Object {$_.State -eq "Running"})
    Write-Host 'Job queue length is ' $running.count -ForegroundColor Yellow
    if ($running.Count -ge $queueLimit) {
        write-host "Waiting for spot in queue" -ForegroundColor Green
        $running | Wait-Job -Any | Out-Null
    }
    write-output "Starting Job for computer $($machinename)"
    # Start jobs here
    Start-Job -InitializationScript $init -ArgumentList $($machinename), $username, $password -ScriptBlock {Do-Work $args[0] $args[1] $args[2]} -Name $($machinename) | Out-Null
    write-host ""
}

write-host ""
write-host "Waiting for remaining jobs to complete" -ForegroundColor Green

$runcount = (@(Get-Job | Where-Object {$_.State -eq "Running"})).count
$runcount
Do {
    $running = @(Get-Job | Where-Object {$_.State -eq "Running"})
    If ($running.count -lt $runcount){
        $runcount = $running.count
        $runcount
    }
}
While ($running.count -gt 0)

Get-Job | Wait-Job
write-host ""
write-host "Done" -ForegroundColor Green

foreach ($job in get-job) {
    Receive-Job -Job $job -Keep | out-file $logfile -Append
    "-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-" | out-file $logfile -Append
}
$inFile   = $logfile


$sendTo = @('username@domain.com') # This is for script testing only
$sendFrom = “Script Reporting <noreply@domain.com>"
$smtp = 'smtp.domain.com'
$port = '25'
$subject = "Log for WindowsSensor Installation $runday"
$content = Get-Content $inFile | Out-String
$content = [string]::Join("`n",$content)
Send-MailMessage -To $sendTo -From $sendFrom -Subject $subject -Body $content -SmtpServer $smtp -Port $port

Open in new window

This should be close.  Look at the end and, if your Exchange/SMTP mail server won't allow relaying, simply delete the last 9 lines.
This should prompt you for your credentials then run the script in parallel against a provided CSV file of machine names.  The column header for the Machine Name field MUST be "Machine Name" unless you choose to modify the code.
Avatar of Mike

ASKER

I getting the following error message below... Do you have any idea's  


Exception calling "GetFileNameWithoutExtension" with "1" argument(s): "Illegal characters in path."
At line:10 char:56
+ $scriptname = [io.path]::GetFileNameWithoutExtension($(Split-Path $script -Leaf) ...
+                                                        ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentException

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of David Johnson, CD
David Johnson, CD
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
David, $machinearray is called on line 80 of my script and should never be called within the $init scriptblock.

The error in line 10 is generated because the script presumes it has been saved and not merely in the editor of ISE.  Save the script somewhere and change the appropriate values for the name of the file containing the computer names in line 7.

Mike, what is your level of Powershell proficiency?  If you are not proficient, I can provide you with a commented copy of the code.
I use a framework I wrote in Powershell to perform parallel execution across hundreds of sites simultaneously and that is what I used for this script.
Avatar of Mike

ASKER

I am new to PS... I know how to write a simple script... but nothing to the level of this one.
Avatar of Mike

ASKER

Thanks, the script worked
Avatar of Mike

ASKER

Thanks for the help
I find it a bit odd that I did not receive even partial credit as your solution originated from my script.